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

转载请标明地址: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那么发布版的语音还是没声音

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

发布版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

运行效果图

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

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

1、初始化

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

2、配置map参数

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

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

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


导航类:

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


运行效果:

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



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

遇到的大坑:

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

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

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

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

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

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

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

2、仿DrawerLayout的覆盖型侧滑菜单,研究了好久,可参考:http://blog.csdn.net/gaolei1201/article/details/50404941https://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(包括附近车辆、规划路径、行驶距离、行驶轨迹记录,导航等)


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

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