Android百度地图实例详解之仿摩拜单车APP(包括附近车辆、规划路径、行驶距离、行驶轨迹记录,导航等)

标签: android百度地图行驶轨迹记录共享单车行驶距离和时间
2017-03-08 20:05 4488人阅读 评论(15) 收藏 举报
 分类:
原创(37) 

版权声明:本文为博主原创文章,未经博主允许不得转载。

转载请标明地址:http://blog.csdn.net/gaolei1201/article/details/60876811

2016一路有你,2017一起奋斗!

最近共享单车很火,动辄几亿美刀,屌丝的我只有羡慕的份。啥时候自己也能创一番事业呢?我眉头紧皱深深地思索着。个人认为LBS是移动互联网最主要的特征之一,自己以前没做过地图有关的项目,看到网上也没有完整有关地图的项目,就想起模仿一下摩拜单车app,我这个小项目包括附近车辆、规划路径、行驶距离、行驶轨迹记录、导航等(也挺全的哈);

需要注意:

0、,其中的附近车辆用的是假数据,实际项目中你上传自己的经纬度然后服务器端会返回给你附近车辆列表显示出来就行。行驶轨迹记录都是保存在本地数据库,实际项目中你可以隔几秒上传一次踩点列表到服务器,防止APP被杀死或其它异常导致以前踩点消失

1、距离是取两个位置点的直线距离,DistanceUtil.getDistance(lastLatLng, currentLatLng)。然后把所有这些距离相加就是总距离,这是通常算法
2、实际项目中可定时你上传当前位置,然后服务器返回给你附近自行车数据,你展示一下就行。

3、行驶轨迹就是开启后台Service每隔几秒收集一次经纬度,到最后必须把所有经纬度上传到服务器,这样就算app被卸载,重新安装你还可以获取到行驶轨迹。有两种思路,一是边收集变上传到服务器或数据库,这样可以防止手机重启或App被杀死导致以前的数据消失,二是等结束进程时上传到服务器。

4、百度内置导航语音播报的问题:能正常导航,但是无法语音播报?

除了地图显示、定位、导航需要的配置之外,tts播报需要添加白名单,点击进入配置地址。可参考:http://blog.csdn.net/chentravelling/article/details/51435976。

还有就是要分清提交时是debug版和release版的MD5,如果是测试版MD5那么发布版的语音还是没声音

发布版md5或sha获取方法:keytool -list -v -keystore /Users/gaolei/Work/CompanyProject/Bike/BiuBike/BiuBike/biubike.jks
测试版md5或sha获取方法:keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android

百度地图开放平台注册不需要公司营业执照什么的,个人就能注册,地址:http://lbsyun.baidu.com。

首先建议大家吧百度地图API的demo下载下来研究一下,它包含我们用到的所有知识点,你再把资源整合一下就行了。SDK的Demo下载地址:http://lbsyun.baidu.com/sdk/download?selected=mapsdk_basicmap,mapsdk_searchfunction,mapsdk_lbscloudsearch,mapsdk_calculationtool,mapsdk_radar

运行效果图

   

下面简单介绍一下有关内容,有需要的可以下载源码运行研究

1、初始化

SDKInitializer.initialize(getApplicationContext());//我测试在Application的onCreate()不行,必须在activity的onCreate()中

2、配置map参数

[html] view plaincopy
  1. <span style="font-size:14px;"> private void initMap() {
  2. // 地图初始化
  3. mMapView = (MapView) findViewById(R.id.id_bmapView);
  4. mBaiduMap = mMapView.getMap();
  5. // 开启定位图层
  6. mBaiduMap.setMyLocationEnabled(true);
  7. // 定位初始化
  8. mlocationClient = new LocationClient(this);
  9. mlocationClient.registerLocationListener(myListener);
  10. LocationClientOption option = new LocationClientOption();
  11. option.setOpenGps(true); // 打开gps
  12. option.setCoorType("bd09ll"); // 设置坐标类型
  13. option.setScanSpan(5000);//设置onReceiveLocation()获取位置的频率
  14. option.setIsNeedAddress(true);//如想获得具体位置就需要设置为true
  15. mlocationClient.setLocOption(option);
  16. mlocationClient.start();
  17. mCurrentMode = MyLocationConfiguration.LocationMode.FOLLOWING;
  18. mBaiduMap.setMyLocationConfigeration(new MyLocationConfiguration(
  19. mCurrentMode, true, null));
  20. myOrientationListener = new MyOrientationListener(this);
  21. //通过接口回调来实现实时方向的改变
  22. myOrientationListener.setOnOrientationListener(new MyOrientationListener.OnOrientationListener() {
  23. @Override
  24. public void onOrientationChanged(float x) {
  25. mCurrentX = x;
  26. }
  27. });
  28. myOrientationListener.start();
  29. mSearch = RoutePlanSearch.newInstance();
  30. mSearch.setOnGetRoutePlanResultListener(this);
  31. initMarkerClickEvent();
  32. }</span>

3、获取当前地址

[html] view plaincopy
  1. <span style="font-size:14px;">public class MyLocationListenner implements BDLocationListener {
  2. @Override
  3. public void onReceiveLocation(BDLocation bdLocation) {
  4. // map view 销毁后不在处理新接收的位置
  5. if (bdLocation == null || mMapView == null) {
  6. return;
  7. }
  8. MyLocationData locData = new MyLocationData.Builder()
  9. .accuracy(bdLocation.getRadius())
  10. .direction(mCurrentX)//设定图标方向     // 此处设置开发者获取到的方向信息,顺时针0-360
  11. .latitude(bdLocation.getLatitude())
  12. .longitude(bdLocation.getLongitude()).build();
  13. mBaiduMap.setMyLocationData(locData);
  14. currentLatitude = bdLocation.getLatitude();
  15. currentLongitude = bdLocation.getLongitude();
  16. current_addr.setText(bdLocation.getAddrStr());
  17. currentLL = new LatLng(bdLocation.getLatitude(),
  18. bdLocation.getLongitude());
  19. startNodeStr = PlanNode.withLocation(currentLL);
  20. //option.setScanSpan(5000),每隔5000ms这个方法就会调用一次,而有些我们只想调用一次,所以要判断一下isFirstLoc
  21. if (isFirstLoc) {
  22. isFirstLoc = false;
  23. LatLng ll = new LatLng(bdLocation.getLatitude(),
  24. bdLocation.getLongitude());
  25. MapStatus.Builder builder = new MapStatus.Builder();
  26. //地图缩放比设置为18
  27. builder.target(ll).zoom(18.0f);
  28. mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
  29. changeLatitude = bdLocation.getLatitude();
  30. changeLongitude = bdLocation.getLongitude();
  31. if (!isServiceLive) {
  32. addOverLayout(currentLatitude, currentLongitude);
  33. }
  34. }
  35. }
  36. }</span>

4、开启service来每隔几秒收集一次经纬度信息,保存到列表,然后通过broadcast把数据传到MainActivity来更新时间和距离UI信息

[html] view plaincopy
  1. <span style="font-size:14px;">public class RouteService extends Service {
  2. private double currentLatitude, currentLongitude;
  3. private LocationClient mlocationClient = null;
  4. private MylocationListener mlistener;
  5. private BitmapDescriptor mIconLocation;
  6. private MyOrientationListener myOrientationListener;
  7. private float mCurrentX;
  8. //定位图层显示方式
  9. private MyLocationConfiguration.LocationMode locationMode;
  10. AllInterface.IUpdateLocation iUpdateLocation;
  11. public ArrayList<RoutePoint> routPointList = new ArrayList<RoutePoint>();
  12. public  int totalDistance = 0;
  13. public  float totalPrice = 0;
  14. public  long beginTime = 0, totalTime = 0;
  15. Notification notification;
  16. RemoteViews contentView;
  17. public void setiUpdateLocation(AllInterface.IUpdateLocation iUpdateLocation) {
  18. this.iUpdateLocation = iUpdateLocation;
  19. }
  20. public void onCreate() {
  21. Log.d("gaolei", "RouteService--------onCreate-------------");
  22. super.onCreate();
  23. beginTime = System.currentTimeMillis();
  24. //        RouteDBHelper dbHelper = new RouteDBHelper(this);
  25. //        // 只有调用了DatabaseHelper的getWritableDatabase()方法或者getReadableDatabase()方法之后,才会创建或打开一个连接
  26. //        SQLiteDatabase sqliteDatabase = dbHelper.getReadableDatabase();
  27. totalTime = 0;
  28. totalDistance = 0;
  29. totalPrice = 0;
  30. routPointList.clear();
  31. }
  32. public int onStartCommand(Intent intent, int flags, int startId) {
  33. Log.d("gaolei", "RouteService--------onStartCommand---------------");
  34. initLocation();//初始化LocationgClient
  35. initNotification();
  36. Utils.acquireWakeLock(this);
  37. // 开启轨迹记录线程
  38. return super.onStartCommand(intent, flags, startId);
  39. }
  40. private void initNotification() {
  41. int icon = R.mipmap.bike_icon2;
  42. contentView = new RemoteViews(getPackageName(), R.layout.notification_layout);
  43. notification = new NotificationCompat.Builder(this).setContent(contentView).setSmallIcon(icon).build();
  44. Intent notificationIntent = new Intent(this, MainActivity.class);
  45. notificationIntent.putExtra("flag", "notification");
  46. notification.contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
  47. }
  48. private void initLocation() {
  49. mIconLocation = BitmapDescriptorFactory
  50. .fromResource(R.mipmap.location_marker);
  51. locationMode = MyLocationConfiguration.LocationMode.NORMAL;
  52. //定位服务的客户端。宿主程序在客户端声明此类,并调用,目前只支持在主线程中启动
  53. mlocationClient = new LocationClient(this);
  54. mlistener = new MylocationListener();
  55. //        initMarkerClickEvent();
  56. //注册监听器
  57. mlocationClient.registerLocationListener(mlistener);
  58. //配置定位SDK各配置参数,比如定位模式、定位时间间隔、坐标系类型等
  59. LocationClientOption mOption = new LocationClientOption();
  60. //设置坐标类型
  61. mOption.setCoorType("bd09ll");
  62. //设置是否需要地址信息,默认为无地址
  63. mOption.setIsNeedAddress(true);
  64. //设置是否打开gps进行定位
  65. mOption.setOpenGps(true);
  66. //设置扫描间隔,单位是毫秒 当<1000(1s)时,定时定位无效
  67. int span = 10000;
  68. mOption.setScanSpan(span);
  69. //设置 LocationClientOption
  70. mlocationClient.setLocOption(mOption);
  71. //初始化图标,BitmapDescriptorFactory是bitmap 描述信息工厂类.
  72. mIconLocation = BitmapDescriptorFactory
  73. .fromResource(R.mipmap.location_marker);
  74. myOrientationListener = new MyOrientationListener(this);
  75. //通过接口回调来实现实时方向的改变
  76. myOrientationListener.setOnOrientationListener(new MyOrientationListener.OnOrientationListener() {
  77. @Override
  78. public void onOrientationChanged(float x) {
  79. mCurrentX = x;
  80. }
  81. });
  82. //        mSearch = RoutePlanSearch.newInstance();
  83. //        mSearch.setOnGetRoutePlanResultListener(this);
  84. //        //开启定位
  85. //        mBaiduMap.setMyLocationEnabled(true);
  86. if (!mlocationClient.isStarted()) {
  87. mlocationClient.start();
  88. }
  89. myOrientationListener.start();
  90. }
  91. private void startNotifi(String time, String distance, String price) {
  92. startForeground(1, notification);
  93. contentView.setTextViewText(R.id.bike_time, time);
  94. contentView.setTextViewText(R.id.bike_distance, distance);
  95. contentView.setTextViewText(R.id.bike_price, price);
  96. }
  97. public IBinder onBind(Intent intent) {
  98. Log.d("gaolei", "onBind-------------");
  99. return null;
  100. }
  101. public boolean onUnBind(Intent intent) {
  102. Log.d("gaolei", "onBind-------------");
  103. return false;
  104. }
  105. @Override
  106. public void onDestroy() {
  107. super.onDestroy();
  108. mlocationClient.stop();
  109. myOrientationListener.stop();
  110. Log.d("gaolei", "RouteService----0nDestroy---------------");
  111. Gson gson = new Gson();
  112. String routeListStr = gson.toJson(routPointList);
  113. Log.d("gaolei", "RouteService----routeListStr-------------" + routeListStr);
  114. Bundle bundle = new Bundle();
  115. bundle.putString("totalTime", totalTime + "");
  116. bundle.putString("totalDistance", totalDistance + "");
  117. bundle.putString("totalPrice", totalPrice + "");
  118. bundle.putString("routePoints", routeListStr);
  119. Intent intent = new Intent(this, RouteDetailActivity.class);
  120. intent.putExtras(bundle);
  121. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  122. startActivity(intent);
  123. if (routPointList.size() > 2)
  124. insertData(routeListStr);
  125. Utils.releaseWakeLock();
  126. stopForeground(true);
  127. }
  128. //所有的定位信息都通过接口回调来实现
  129. public class MylocationListener implements BDLocationListener {
  130. //定位请求回调接口
  131. private boolean isFirstIn = true;
  132. //定位请求回调函数,这里面会得到定位信息
  133. @Override
  134. public void onReceiveLocation(BDLocation bdLocation) {
  135. if (null == bdLocation) return;
  136. //"4.9E-324"表示目前所处的环境(室内或者是网络状况不佳)造成无法获取到经纬度
  137. if ("4.9E-324".equals(String.valueOf(bdLocation.getLatitude())) || "4.9E-324".equals(String.valueOf(bdLocation.getLongitude()))) {
  138. return;
  139. }//过滤百度定位失败
  140. Log.d("gaolei", "RouteService---------getAddrStr()-------------" + bdLocation.getAddrStr());
  141. double routeLat = bdLocation.getLatitude();
  142. double routeLng = bdLocation.getLongitude();
  143. RoutePoint routePoint = new RoutePoint();
  144. routePoint.setRouteLat(routeLat);
  145. routePoint.setRouteLng(routeLng);
  146. if (routPointList.size() == 0)
  147. routPointList.add(routePoint);
  148. else {
  149. RoutePoint lastPoint = routPointList.get(routPointList.size() - 1);
  150. if (routeLat == lastPoint.getRouteLat() && routeLng == lastPoint.getRouteLng()) {
  151. } else {
  152. LatLng lastLatLng = new LatLng(lastPoint.getRouteLat(),
  153. lastPoint.getRouteLng());
  154. LatLng currentLatLng = new LatLng(routeLat, routeLng);
  155. if (routeLat > 0 && routeLng > 0) {//经纬度都不能为0
  156. double distantce = DistanceUtil.getDistance(lastLatLng, currentLatLng);
  157. //                       大于5米才加入列表
  158. if (distantce > 5) {
  159. routPointList.add(routePoint);
  160. totalDistance += distantce;
  161. }
  162. }
  163. }
  164. }
  165. totalTime = (int) (System.currentTimeMillis() - beginTime) / 1000 / 60;
  166. totalPrice = (float) (Math.floor(totalTime / 30) * 0.5 + 0.5);
  167. //            Log.d("gaolei", "biginTime--------------" + beginTime);
  168. Log.d("gaolei", "totalTime--------------" + totalTime);
  169. Log.d("gaolei", "totalDistance--------------" + totalDistance);
  170. startNotifi(totalTime + "分钟", totalDistance + "米", totalPrice + "元");
  171. Intent intent = new Intent("com.locationreceiver");
  172. Bundle bundle = new Bundle();
  173. bundle.putString("totalTime", totalTime + "分钟");
  174. bundle.putString("totalDistance", totalDistance + "米");
  175. bundle.putString("totalPrice", totalPrice + "元");
  176. intent.putExtras(bundle);
  177. sendBroadcast(intent);
  178. }
  179. }
  180. public static class NetWorkReceiver extends BroadcastReceiver
  181. {
  182. public NetWorkReceiver() {
  183. }
  184. @Override
  185. public void onReceive(Context context, Intent intent) {
  186. NetworkInfo.State wifiState = null;
  187. NetworkInfo.State mobileState = null;
  188. ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
  189. wifiState = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState();
  190. mobileState = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState();
  191. if (wifiState != null && mobileState != null
  192. && NetworkInfo.State.CONNECTED != wifiState
  193. && NetworkInfo.State.CONNECTED == mobileState) {
  194. //                Toast.makeText(context, context.getString(R.string.net_mobile), Toast.LENGTH_SHORT).show();
  195. // 手机网络连接成功
  196. } else if (wifiState != null && mobileState != null
  197. && NetworkInfo.State.CONNECTED != wifiState
  198. && NetworkInfo.State.CONNECTED != mobileState) {
  199. //                Toast.makeText(context, context.getString(R.string.net_none), Toast.LENGTH_SHORT).show();
  200. // 手机没有任何的网络
  201. } else if (wifiState != null && NetworkInfo.State.CONNECTED == wifiState) {
  202. // 无线网络连接成功
  203. //                Toast.makeText(context, context.getString(R.string.net_wifi), Toast.LENGTH_SHORT).show();
  204. }
  205. }
  206. }
  207. public void insertData(String routeListStr) {
  208. ContentValues values = new ContentValues();
  209. // 向该对象中插入键值对,其中键是列名,值是希望插入到这一列的值,值必须和数据当中的数据类型一致
  210. values.put("cycle_date", Utils.getDateFromMillisecond(beginTime));
  211. values.put("cycle_time", totalTime);
  212. values.put("cycle_distance", totalDistance);
  213. values.put("cycle_price", totalPrice);
  214. values.put("cycle_points", routeListStr);
  215. // 创建DatabaseHelper对象
  216. RouteDBHelper dbHelper = new RouteDBHelper(this);
  217. // 得到一个可写的SQLiteDatabase对象
  218. SQLiteDatabase sqliteDatabase = dbHelper.getWritableDatabase();
  219. // 调用insert方法,就可以将数据插入到数据库当中
  220. // 第一个参数:表名称
  221. // 第二个参数:SQl不允许一个空列,如果ContentValues是空的,那么这一列被明确的指明为NULL值
  222. // 第三个参数:ContentValues对象
  223. sqliteDatabase.insert("cycle_route", null, values);
  224. sqliteDatabase.close();
  225. }
  226. }</span>

5、结束行程,可以查看行驶轨迹

[html] view plaincopy
  1. <span style="font-size:14px;">public class RouteDetailActivity extends BaseActivity {
  2. private MapView route_detail_mapview;
  3. BaiduMap routeBaiduMap;
  4. private BitmapDescriptor startBmp, endBmp;
  5. private MylocationListener mlistener;
  6. LocationClient mlocationClient;
  7. TextView total_time, total_distance, total_price;
  8. public ArrayList<RoutePoint> routePoints;
  9. public static boolean completeRoute = false;
  10. String time, distance, price, routePointsStr;
  11. public void onCreate(Bundle savedInstanceState) {
  12. super.onCreate(savedInstanceState);
  13. setContentView(R.layout.activity_route_detail);
  14. setStatusBar();
  15. route_detail_mapview = (MapView) findViewById(R.id.route_detail_mapview);
  16. total_time = (TextView) findViewById(R.id.total_time);
  17. total_distance = (TextView) findViewById(R.id.total_distance);
  18. total_price = (TextView) findViewById(R.id.total_pricce);
  19. routeBaiduMap = route_detail_mapview.getMap();
  20. route_detail_mapview.showZoomControls(false);
  21. startBmp = BitmapDescriptorFactory.fromResource(R.mipmap.route_start);
  22. endBmp = BitmapDescriptorFactory.fromResource(R.mipmap.route_end);
  23. initMap();
  24. Intent intent = getIntent();
  25. String time = intent.getStringExtra("totalTime");
  26. String distance = intent.getStringExtra("totalDistance");
  27. String price = intent.getStringExtra("totalPrice");
  28. routePointsStr = intent.getStringExtra("routePoints");
  29. routePoints = new Gson().fromJson(routePointsStr, new TypeToken<List<RoutePoint>>() {
  30. }.getType());
  31. List<LatLng> points = new ArrayList<LatLng>();
  32. for (int i = 0; i < routePoints.size(); i++) {
  33. RoutePoint point = routePoints.get(i);
  34. LatLng latLng = new LatLng(point.getRouteLat(), point.getRouteLng());
  35. Log.d("gaolei", "point.getRouteLat()----show-----" + point.getRouteLat());
  36. Log.d("gaolei", "point.getRouteLng()----show-----" + point.getRouteLng());
  37. points.add(latLng);
  38. }
  39. if (points.size() > 2) {
  40. OverlayOptions ooPolyline = new PolylineOptions().width(10)
  41. .color(0xFF36D19D).points(points);
  42. routeBaiduMap.addOverlay(ooPolyline);
  43. RoutePoint startPoint = routePoints.get(0);
  44. LatLng startPosition = new LatLng(startPoint.getRouteLat(), startPoint.getRouteLng());
  45. MapStatus.Builder builder = new MapStatus.Builder();
  46. builder.target(startPosition).zoom(18.0f);
  47. routeBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
  48. RoutePoint endPoint = routePoints.get(routePoints.size() - 1);
  49. LatLng endPosition = new LatLng(endPoint.getRouteLat(), endPoint.getRouteLng());
  50. addOverLayout(startPosition, endPosition);
  51. }
  52. total_time.setText("骑行时长:" + time + "分钟");
  53. total_distance.setText("骑行距离:" + distance + "米");
  54. total_price.setText("余额支付:" + price + "元");
  55. }
  56. private void initMap() {
  57. mlocationClient = new LocationClient(this);
  58. //        mlistener = new MylocationListener();
  59. //        mlocationClient.registerLocationListener(mlistener);
  60. LocationClientOption mOption = new LocationClientOption();
  61. //设置坐标类型
  62. mOption.setCoorType("bd09ll");
  63. //设置是否需要地址信息,默认为无地址
  64. mOption.setIsNeedAddress(true);
  65. //设置是否打开gps进行定位
  66. mOption.setOpenGps(true);
  67. //设置扫描间隔,单位是毫秒 当<1000(1s)时,定时定位无效
  68. int span = 10000;
  69. mOption.setScanSpan(span);
  70. //设置 LocationClientOption
  71. mlocationClient.setLocOption(mOption);
  72. if (!mlocationClient.isStarted()) {
  73. mlocationClient.start();
  74. }
  75. UiSettings settings=routeBaiduMap.getUiSettings();
  76. settings.setScrollGesturesEnabled(true);
  77. }
  78. public class MylocationListener implements BDLocationListener {
  79. //定位请求回调接口
  80. private boolean isFirstIn = true;
  81. //定位请求回调函数,这里面会得到定位信息
  82. @Override
  83. public void onReceiveLocation(BDLocation bdLocation) {
  84. //判断是否为第一次定位,是的话需要定位到用户当前位置
  85. if (isFirstIn) {
  86. Log.d("gaolei", "onReceiveLocation----------RouteDetail-----" + bdLocation.getAddrStr());
  87. //                LatLng currentLL = new LatLng(bdLocation.getLatitude(),
  88. //                        bdLocation.getLongitude());
  89. startNodeStr = PlanNode.withLocation(currentLL);
  90. //                MapStatus.Builder builder = new MapStatus.Builder();
  91. //                builder.target(currentLL).zoom(18.0f);
  92. //                routeBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
  93. isFirstIn = false;
  94. }
  95. }
  96. }
  97. private void addOverLayout(LatLng startPosition, LatLng endPosition) {
  98. //先清除图层
  99. //        mBaiduMap.clear();
  100. // 定义Maker坐标点
  101. // 构建MarkerOption,用于在地图上添加Marker
  102. MarkerOptions options = new MarkerOptions().position(startPosition)
  103. .icon(startBmp);
  104. // 在地图上添加Marker,并显示
  105. routeBaiduMap.addOverlay(options);
  106. MarkerOptions options2 = new MarkerOptions().position(endPosition)
  107. .icon(endBmp);
  108. // 在地图上添加Marker,并显示
  109. routeBaiduMap.addOverlay(options2);
  110. }
  111. public void onDestroy() {
  112. super.onDestroy();
  113. routeBaiduMap.setMyLocationEnabled(false);
  114. mlocationClient.stop();
  115. completeRoute = false;
  116. }
  117. public void finishActivity(View view) {
  118. completeRoute = true;
  119. finish();
  120. }
  121. public boolean onKeyDown(int keyCode, KeyEvent event) {
  122. if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
  123. completeRoute = true;
  124. finish();
  125. return true;
  126. }
  127. return super.onKeyDown(keyCode, event);
  128. }
  129. }</span>

导航类:

[html] view plaincopy
  1. <span style="font-size:14px;">/**
  2. * Created by GaoLei on 17/3/31.
  3. * 这个工具类实现了调用内置导航和打开第三方App导航
  4. * 1.assets中的文件必须拷贝到项目
  5. * 2.想使用内置导航,必须初始化导航, NavUtil.initNavi(this);
  6. */
  7. public class NavUtil {
  8. public static final int BaiduNavi = 1, GaodeNavi = 2, InnerNavi = 0;
  9. public static List<Activity> activityList = new LinkedList<Activity>();
  10. public static final String ROUTE_PLAN_NODE = "routePlanNode";
  11. static String authinfo = null;
  12. /**
  13. * 弹出导航选择dialog
  14. */
  15. public static void showChoiceNaviWayDialog(final Activity activity, final LatLng startLL, final LatLng endLL, final String start_place, final String destination) {
  16. final NaviSelectDialog rcd = new NaviSelectDialog(activity);
  17. rcd.setCanceledOnTouchOutside(false);
  18. rcd.setCancelable(false);
  19. final ArrayList<String> mapApps = new ArrayList<String>();
  20. mapApps.add(activity.getString(R.string.inner_navi));
  21. if (Utils.hasApp(activity, Utils.APP_BAIDU_MAP)) {
  22. mapApps.add(activity.getString(R.string.baidu_navi));
  23. }
  24. if (Utils.hasApp(activity, Utils.APP_AMAP)) {
  25. mapApps.add(activity.getString(R.string.gaode_navi));
  26. }
  27. rcd.setItems(mapApps, new NaviSelectDialog.OnDlgItemClickListener() {
  28. @Override
  29. public void onEnsureClicked(Dialog dialog, String value, boolean isChecked) {
  30. dialog.dismiss();
  31. if (activity.getString(R.string.inner_navi).equals(value)) {
  32. launchNavigatorViaPoints(activity, startLL, endLL);
  33. //                   startInnerNavi(activity, startLL, endLL);
  34. }
  35. if (activity.getString(R.string.baidu_navi).equals(value)) {
  36. //                    startNative_Baidu(activity, startLL, endLL, start_place, destination);
  37. startBikingNavi(activity, startLL, endLL);
  38. } else if (activity.getString(R.string.gaode_navi).equals(value)) {
  39. startGaodeNavi(activity, startLL, endLL, start_place);
  40. }
  41. if (isChecked) {
  42. //记住我的选择
  43. }
  44. }
  45. public void onCancleClicked(Dialog dialog) {
  46. dialog.dismiss();
  47. }
  48. }, true).show();
  49. }
  50. private static void launchNavigatorViaPoints(final Activity activity, LatLng startLL, LatLng endLL) {
  51. //这里给出一个起终点示例,实际应用中可以通过POI检索、外部POI来源等方式获取起终点坐标
  52. activityList.add(activity);
  53. final BNRoutePlanNode sNode = new BNRoutePlanNode(startLL.longitude, startLL.latitude, null, "从这里开始", BNRoutePlanNode.CoordinateType.BD09LL);
  54. final BNRoutePlanNode eNode = new BNRoutePlanNode(endLL.longitude, endLL.latitude, null, "到这里结束", BNRoutePlanNode.CoordinateType.BD09LL);
  55. if (sNode != null && eNode != null) {
  56. List<BNRoutePlanNode> points = new ArrayList<BNRoutePlanNode>();
  57. points.add(sNode);
  58. points.add(eNode);
  59. //距离太近toast提示(100米内)
  60. double dis = DistanceUtil.getDistance(new LatLng(sNode.getLatitude(), sNode.getLongitude()), new LatLng(eNode.getLatitude(), eNode.getLongitude()));
  61. if (dis <= 100) {
  62. Toast.makeText(activity, "起点、途经点、终点距离太近", Toast.LENGTH_SHORT).show();
  63. return;
  64. }
  65. BaiduNaviManager.getInstance().launchNavigator(activity, points, 1, true, new BaiduNaviManager.RoutePlanListener() {
  66. public void onJumpToNavigator() {
  67. /*
  68. * 设置途径点以及resetEndNode会回调该接口
  69. */
  70. for (Activity ac : activityList) {
  71. if (ac.getClass().getName().endsWith("BNDemoGuideActivity")) {
  72. return;
  73. }
  74. }
  75. Intent intent = new Intent(activity, BDInnerNaviActivity.class);
  76. Bundle bundle = new Bundle();
  77. bundle.putSerializable(ROUTE_PLAN_NODE, (BNRoutePlanNode) sNode);
  78. intent.putExtras(bundle);
  79. activity.startActivity(intent);
  80. }
  81. public void onRoutePlanFailed() {
  82. // TODO Auto-generated method stub
  83. Toast.makeText(activity, "算路失败", Toast.LENGTH_SHORT).show();
  84. }
  85. });
  86. }
  87. }
  88. /**
  89. * 启动百度地图骑行导航(Native)
  90. */
  91. private static void startBikingNavi(Activity activity, LatLng startLL, LatLng endLL) {
  92. //距离太近toast提示(100米内)
  93. double dis = DistanceUtil.getDistance(new LatLng(startLL.latitude, startLL.longitude), new LatLng(endLL.latitude, endLL.longitude));
  94. if (dis <= 100) {
  95. Toast.makeText(activity, "起点、途经点、终点距离太近", Toast.LENGTH_SHORT).show();
  96. return;
  97. }
  98. // 构建 导航参数
  99. NaviParaOption para = new NaviParaOption()
  100. .startPoint(startLL).endPoint(endLL);
  101. try {
  102. BaiduMapNavigation.openBaiduMapBikeNavi(para, activity);
  103. } catch (BaiduMapAppNotSupportNaviException e) {
  104. e.printStackTrace();
  105. }
  106. }
  107. /**
  108. * 启动百度地图导航(Native)
  109. */
  110. public void startNavi(Activity activity, LatLng pt1, LatLng pt2) {
  111. // 构建 导航参数
  112. NaviParaOption para = new NaviParaOption()
  113. .startPoint(pt1).endPoint(pt2)
  114. .startName("天安门").endName("百度大厦");
  115. try {
  116. BaiduMapNavigation.openBaiduMapNavi(para, activity);
  117. } catch (BaiduMapAppNotSupportNaviException e) {
  118. e.printStackTrace();
  119. showDialog(activity);
  120. }
  121. }
  122. /**
  123. * 启动百度地图驾车路线规划
  124. */
  125. public void startRoutePlanDriving(Activity activity, LatLng pt1, LatLng pt2) {
  126. // 构建 route搜索参数
  127. RouteParaOption para = new RouteParaOption()
  128. .startPoint(pt1)
  129. .endPoint(pt2);
  130. try {
  131. BaiduMapRoutePlan.openBaiduMapDrivingRoute(para, activity);
  132. } catch (Exception e) {
  133. e.printStackTrace();
  134. showDialog(activity);
  135. }
  136. }
  137. /**
  138. * 通过Uri跳转到百度地图导航
  139. */
  140. public static void startNative_Baidu(Activity activity, LatLng pt1, LatLng pt2, String start_address, String end_address) {
  141. try {
  142. double dis = DistanceUtil.getDistance(new LatLng(pt1.latitude,pt1.longitude), new LatLng(pt2.latitude,pt2.longitude));
  143. if (dis <= 100) {
  144. Toast.makeText(activity, "起点、途经点、终点距离太近", Toast.LENGTH_SHORT).show();
  145. return;
  146. }
  147. String start_latlng = pt1.latitude + "," + pt1.longitude;
  148. String end_latlng = pt2.latitude + "," + pt2.longitude;
  149. Intent intent = Intent.getIntent("intent://map/direction?origin=latlng:"+start_latlng+"|name:"+"Start"+"&destination=latlng:"+end_latlng+"|name:"+"End"+"&mode=riding&src=这里随便写#Intent;scheme=bdapp;package=com.baidu.BaiduMap;end");
  150. Log.d("gaolei", "---------------" + start_address + "," + end_address);
  151. activity.startActivity(intent);
  152. } catch (Exception e) {
  153. e.printStackTrace();
  154. Toast.makeText(activity, "地址解析错误", Toast.LENGTH_SHORT).show();
  155. }
  156. }
  157. /**
  158. * 启动高德地图驾车路线规划
  159. */
  160. public static void startGaodeNavi(Activity activity, LatLng pt1, LatLng pt2, String start_place) {
  161. try {
  162. Intent intent = new Intent();
  163. double sLat = pt1.latitude, sLon = pt1.longitude, eLat = pt2.latitude, eLon = pt2.longitude;
  164. String poiAddress = LocationManager.getInstance().getAddress();
  165. Log.d("gaolei", "poiAddress---------gaode-----------" + poiAddress);
  166. intent.setData(android.net.Uri
  167. .parse("androidamap://navi?sourceApplication=yongche&poiname=" + start_place + "&lat="
  168. + eLat
  169. + "&lon="
  170. + eLon + "&dev=0&style=2"));
  171. intent.addCategory("android.intent.category.DEFAULT");
  172. intent.setPackage("com.autonavi.minimap");
  173. activity.startActivity(intent);
  174. } catch (Exception e) {
  175. e.printStackTrace();
  176. }
  177. }
  178. /**
  179. * 路线规划监听器,规划成功后跳转至导航过程页面
  180. */
  181. private static class YCRoutePlanListener implements BaiduNaviManager.RoutePlanListener {
  182. private BNRoutePlanNode mBNRoutePlanNode = null;
  183. private Activity activity;
  184. public YCRoutePlanListener(BNRoutePlanNode node, Activity act) {
  185. mBNRoutePlanNode = node;
  186. activity = act;
  187. }
  188. @Override
  189. public void onJumpToNavigator() {
  190. Intent intent = new Intent(activity, BDInnerNaviActivity.class);
  191. activity.startActivity(intent);
  192. activity.startActivity(intent);
  193. }
  194. @Override
  195. public void onRoutePlanFailed() {
  196. }
  197. }
  198. /**
  199. * 提示未安装百度地图app或app版本过低
  200. */
  201. public void showDialog(final Activity activity) {
  202. AlertDialog.Builder builder = new AlertDialog.Builder(activity);
  203. builder.setMessage("您尚未安装百度地图app或app版本过低,点击确认安装?");
  204. builder.setTitle("提示");
  205. builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
  206. @Override
  207. public void onClick(DialogInterface dialog, int which) {
  208. dialog.dismiss();
  209. OpenClientUtil.getLatestBaiduMapApp(activity);
  210. }
  211. });
  212. builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
  213. @Override
  214. public void onClick(DialogInterface dialog, int which) {
  215. dialog.dismiss();
  216. }
  217. });
  218. builder.create().show();
  219. }
  220. public static void initNavi(final Activity activity) {
  221. BaiduNaviManager.getInstance().init(activity, mSDCardPath, APP_FOLDER_NAME, new BaiduNaviManager.NaviInitListener() {
  222. public void onAuthResult(int status, String msg) {
  223. if (0 == status) {
  224. //                    authinfo = "key校验成功!";
  225. } else {
  226. //                    authinfo = "key校验失败, " + msg;
  227. }
  228. activity.runOnUiThread(new Runnable() {
  229. @Override
  230. public void run() {
  231. //                        Toast.makeText(activity, authinfo, Toast.LENGTH_LONG).show();
  232. }
  233. });
  234. }
  235. public void initSuccess() {
  236. //                Toast.makeText(activity, "百度导航引擎初始化成功", Toast.LENGTH_SHORT).show();
  237. initSetting();
  238. }
  239. public void initStart() {
  240. //                Toast.makeText(activity, "百度导航引擎初始化开始", Toast.LENGTH_SHORT).show();
  241. }
  242. public void initFailed() {
  243. //                Toast.makeText(activity, "百度导航引擎初始化失败", Toast.LENGTH_SHORT).show();
  244. }
  245. }, null, ttsHandler, ttsPlayStateListener);
  246. }
  247. private static void initSetting() {
  248. // 设置是否双屏显示
  249. BNaviSettingManager.setShowTotalRoadConditionBar(BNaviSettingManager.PreViewRoadCondition.ROAD_CONDITION_BAR_SHOW_ON);
  250. // 设置导航播报模式
  251. BNaviSettingManager.setVoiceMode(BNaviSettingManager.VoiceMode.Veteran);
  252. // 是否开启路况
  253. BNaviSettingManager.setRealRoadCondition(BNaviSettingManager.RealRoadCondition.NAVI_ITS_ON);
  254. }
  255. /**
  256. * 内部TTS播报状态回传handler
  257. */
  258. private static Handler ttsHandler = new Handler() {
  259. public void handleMessage(Message msg) {
  260. int type = msg.what;
  261. switch (type) {
  262. case BaiduNaviManager.TTSPlayMsgType.PLAY_START_MSG: {
  263. //                    showToastMsg("Handler : TTS play start");
  264. break;
  265. }
  266. case BaiduNaviManager.TTSPlayMsgType.PLAY_END_MSG: {
  267. //                    showToastMsg("Handler : TTS play end");
  268. break;
  269. }
  270. default:
  271. break;
  272. }
  273. }
  274. };
  275. /**
  276. * 内部TTS播报状态回调接口
  277. */
  278. private static BaiduNaviManager.TTSPlayStateListener ttsPlayStateListener = new BaiduNaviManager.TTSPlayStateListener() {
  279. @Override
  280. public void playEnd() {
  281. //            showToastMsg("TTSPlayStateListener : TTS play end");
  282. }
  283. @Override
  284. public void playStart() {
  285. //            showToastMsg("TTSPlayStateListener : TTS play start");
  286. }
  287. };
  288. }
  289. </span>

运行效果:

     

------------------------------------------------------

遇到的大坑:

1、我的 百度 key肯定是没错,在魅族4.4系统上正常,而在三星C7 和coopad 106(都是6.0系统)不能正常显示,而是一片蓝,获取不到当前位置?如图

解决方法:原因是我设置targetVersion>=23,那么运行到6.0及以上设备时,默认所有权限都不开启,必须动态requestPermission,这里需要位置权限,默认没开启导致此结果,把targetVersion=22就行,当targetVersion<23时,默认开启全部权限。

1.2、地图只显示网格不显示建筑

解决方法:百度开放平台时 debug md5没配置正确,不同电脑或环境 debug md5 不一样,如果用我的项目直接运行可能就会出现这种情况,因为你的电脑环境debug md5和我的电脑环境debug md5不一样。你可以打一个release包 因为release md5如果用同一个签名是不会变的。你也可以在百度地图开放平台自己注册账号配置信息

2、仿DrawerLayout的覆盖型侧滑菜单,研究了好久,可参考:http://blog.csdn.net/gaolei1201/article/details/50404941,https://github.com/gaoleiandroid1201/DrawerLayout

3、位置图标不跟着自己运动,查看自己代码也没有问题啊,调试了好久,跑了不少冤枉路,莫名其妙

解决方法:把百度sdk中的初始化地图和配置参数等代码拷进来代替,果然奏效

4、进程保活,这个不能完全保活,只能尽量保活,除非是被加入白名单或自启应用像微信,但是有些 app像行者和咕咚就算app被杀死了也能活下来,不清楚是怎么实现的,以后有需要在研究。还有就是AlarmManager当手机重启或app被杀死,它也会失效的

5、如果没有第三方导航APP,可以做百度地图内置导航,也耗费了不少时间。主要是官方Demo不能跑通,自带key验证不通过,还要自己研究

6、如果TTS语音导航SDK注册白名单注册不成功一直提示“registed Already”,可参考:http://bbs.lbsyun.baidu.com/forum.php?mod=viewthread&tid=90839

项目源码,点击下载......

Android百度地图实例详解之仿摩拜单车APP(包括附近车辆、规划路径、行驶距离、行驶轨迹记录,导航等)相关推荐

  1. Android百度地图实例详解之仿摩拜单车APP(包括附近车辆、规划路径、行驶距离、行驶轨迹记录,轨迹回放,导航等)

    转载请标明地址:http://blog.csdn.net/gaolei1201/article/details/60876811 2016一路有你,2017一起奋斗! 最近共享单车很火,动辄几亿美刀, ...

  2. 仿摩拜单车APP(包括附近车辆、规划路径、行驶距离、行驶轨迹记录,导航等)

    本文是由奇虎360公司高磊关于使用百度地图仿摩拜单车APP,原文地址:http://blog.csdn.net/gaolei1201/article/details/60876811 最近共享单车很火 ...

  3. android 滑动接听源码,android仿摩拜单车APP、炫酷RecyclerView、卡片滑动、仿饿了么点餐、自定义索引等源码...

    Android精选源码 Android优质博客 前言permissions4m 最初的设计是仅仅做成一个编译器注解框架,在1.0.0版本时,它纯粹地实现了原生 Android 请求流程,关于它的设计思 ...

  4. android 卡片上滑放大,android仿摩拜单车APP、炫酷RecyclerView、卡片滑动、仿饿了么点餐、自定义索引等源码...

    Android精选源码 Android优质博客 前言permissions4m 最初的设计是仅仅做成一个编译器注解框架,在1.0.0版本时,它纯粹地实现了原生 Android 请求流程,关于它的设计思 ...

  5. Android NFC卡实例详解

    Android NFC卡实例详解 公司最近在做一个NFC卡片的工程,经过几天的时间,终于写了一个Demo出来,在此记录下在此过程中遇到的问题.由于之前本人是做iOS的,Android写起来并不是那么的 ...

  6. 微信小程序仿摩拜单车

    本小程序仿摩拜单车的地图显示和拖动部分,单车数据采用周边厕所模拟.index.wxml如下: <map id="map" bindcontroltap="bindc ...

  7. Android 吸入动画效果详解(仿mac退出效果)

    转载自:http://m.blog.csdn.net/blog/leehong2005/9127095 [转]Android 吸入动画效果详解 1,背景 吸入(Inhale)效果,最初我是在iOS上面 ...

  8. android 百度地图驾车导航,百度地图API详解之驾车导航

    本文将向大家介绍如何使用百度地图API提供的驾车导航服务进行开发. 一个简单的示例 驾车导航服务根据传入的起点和终点信息给出从起点到终点的驾车路线,我们先从一个最简单的示例看起: var map = ...

  9. 百度地图API详解之公交导航

    原文地址:http://blog.csdn.net/sup_heaven/article/details/8461593 只是作为备忘!!! 一次调试百度地图多marker事件监听的问题,不知如何解决 ...

最新文章

  1. 对产品经理而言,有一种灾难叫“老板说”
  2. Redis 通配符批量删除key
  3. 计算机二级公共,计算机二级公共基础知识
  4. REG Delete用法
  5. VB.NET工作笔记006---用visual studio2017 编写RESTFUL API
  6. 《编码的奥秘》读后感
  7. 尚硅谷大数据hadoop教程
  8. alienware灯光无法修改问题
  9. Python基础之爬取豆瓣图书信息
  10. python是一种跨平台语言_python是跨平台的语言吗
  11. 密码学(五):数字签名
  12. 时间序列分析的计量经济学方法 - Python中的序列性ARIMA
  13. idea 2021 IDEA的Persistence 窗口 查看ERD关系图
  14. linux gz he xz,gz与xz两种压缩格式的对比
  15. 实体-关系图转换为关系模型
  16. python opencv图像二值化函数_python opencv 二值化 计算白色像素点的实例
  17. 【Windows 安装JDK8】如何安装java JDK8
  18. 云服务器租金注意事项,租用服务器时的5个注意事项
  19. linux 修改群组名称,linux常用命令系列—chgrp-修改所属群组
  20. 学微服务必经之路——Nacos新手入门(下)

热门文章

  1. 9月1日-9月3日(移动web开发——rem适配布局、苏宁易购移动端首页制作)
  2. c语言单片机字符串,C语言与单片机-5-变量输入和输出
  3. Linux-CentOS7离线安装RabbitMq
  4. Oracle 11g笔记——数据库启动
  5. 浅谈斐波那契数列——从递推到矩阵乘法
  6. 荒原狼:大变革时代下的迷茫与矛盾体
  7. 使用微软Monaco Editor 编写在线调试工具
  8. 我的投资案例(3)-看好互联网和金融两大朝阳行业,参投入股垂直金融招聘平台职业梦CareerDream.cn
  9. wxpython dataviewmodel_wxPython + PyOpenGL 打造三维数据分析的利器!|CSDN 博文精选
  10. QA The C compiler “C:/xxx/bin/gcc.exe“ is not able to compile a simple test Program.