使用百度地图API实现驾车导航

做了一个利用百度地图API实现驾车导航的功能,不仅仅是驾车导航,利用这套API还可以实现公交以及步行的导航功能,这里只介绍如何实现驾车导航,步行和公交大同小异。首先来看看最后实现效果:

使用百度地图API实现驾车导航_第1张图片    使用百度地图API实现驾车导航_第2张图片    使用百度地图API实现驾车导航_第3张图片


进入应用后首先显示蓝色点为当前位置,可以输入目的地来形成导航线路(图1),也可以点选地图上任意点来形成导航线路(图2,3),选定点后,在地图上会标注红色定位点,点击开始导航按钮后便会形成最佳驾车线路。


接下来看看实现步骤:

首先是工程结构

          使用百度地图API实现驾车导航_第4张图片

其中libs下面是申请百度开发者后到地图API下下载Android的地图支持包并导入工程,这里不再细说。

然后是布局文件:

[html] view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical" >  
  6.   
  7.     <LinearLayout  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="wrap_content"  
  10.         android:orientation="horizontal" >  
  11.   
  12.         <TextView  
  13.             android:layout_width="wrap_content"  
  14.             android:layout_height="wrap_content"  
  15.             android:text="目的地:"  
  16.             android:textSize="17sp" />  
  17.   
  18.         <EditText  
  19.             android:id="@+id/et_destination"  
  20.             android:layout_width="fill_parent"  
  21.             android:hint="输入目的地名称或在地图上点选"  
  22.             android:textSize="14sp"  
  23.             android:layout_height="wrap_content" />  
  24.     </LinearLayout>  
  25.   
  26.     <LinearLayout  
  27.         android:layout_width="fill_parent"  
  28.         android:layout_height="wrap_content" >  
  29.   
  30.         <Button  
  31.             android:id="@+id/btn_navi"  
  32.             android:layout_width="fill_parent"  
  33.             android:layout_height="wrap_content"  
  34.             android:layout_weight="1"  
  35.             android:text="开始导航" />  
  36.   
  37.         <Button  
  38.             android:id="@+id/btn_clear"  
  39.             android:layout_width="fill_parent"  
  40.             android:layout_height="wrap_content"  
  41.             android:layout_weight="1"  
  42.             android:text="清除路线" />  
  43.     </LinearLayout>  
  44.   
  45.     <com.baidu.mapapi.MapView  
  46.         android:id="@+id/bmapsView"  
  47.         android:layout_width="fill_parent"  
  48.         android:layout_height="fill_parent"  
  49.         android:clickable="true" />  
  50.   
  51. </LinearLayout>  

然后是实现自定义的地图图层MyItemizedOverlay.java,这个类的作用是实现可点击地图图层的作用,点击地图后,便可以显示当前位置的经纬度,并可设置为目的地。

[java] view plain copy print ?
  1. /** 
  2.  * 自定义图层 
  3.  * @author Ryan 
  4.  */  
  5. public class MyItemizedOverlay extends ItemizedOverlay<OverlayItem> {  
  6.       
  7.     private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();      
  8.     private Context context;  
  9.       
  10.     public MyItemizedOverlay(Context context,Drawable drawale) {  
  11.         super(boundCenterBottom(drawale));        
  12.         this.context=context;  
  13.     }  
  14.       
  15.     @Override  
  16.     protected OverlayItem createItem(int i) {  
  17.         return mOverlays.get(i);  
  18.     }  
  19.       
  20.     @Override  
  21.     public int size() {  
  22.         return mOverlays.size();  
  23.     }  
  24.       
  25.     // 点击地图标注显示的内容   
  26.     @Override  
  27.     protected boolean onTap(int index) {  
  28.         //这个方法的重写弹出信息等   
  29.         return true;  
  30.     }  
  31.       
  32.     @Override  
  33.     public void draw(Canvas canvas, MapView mapView, boolean shadow) {  
  34.         super.draw(canvas, mapView, shadow);  
  35.     }  
  36.       
  37.     // Define a method in order to add new OverlayItems to our ArrayList   
  38.     public void addOverlay(OverlayItem overlay) {  
  39.         // add OverlayItems   
  40.         mOverlays.add(overlay);  
  41.         populate();  
  42.     }  
  43.       
  44.     //该方法的重写可以相应点击图标的区域内还是外   
  45.     @Override  
  46.     public boolean onTap(GeoPoint p, MapView mapView) {  
  47.         final SharedPreferences sharedPreferences = context.getSharedPreferences("navigation_pre", Context.MODE_WORLD_WRITEABLE);  
  48.           
  49.         //p获取的经纬度数据是整型变量,需要转换为float类型   
  50.         final float lat=p.getLatitudeE6();  
  51.         final float lon=p.getLongitudeE6();  
  52.         final MapView map = mapView;  
  53.           
  54.         float latitude = sharedPreferences.getFloat("lat"0);  
  55.         if (latitude == 0) {  
  56.             AlertDialog.Builder builder = new AlertDialog.Builder(this.context);  
  57.             builder.setTitle("设置目的地");  
  58.             builder.setMessage("设置选中的点为目的地吗?");  
  59.             builder.setPositiveButton("确定",new OnClickListener() {  
  60.                   
  61.                 @Override  
  62.                 public void onClick(DialogInterface dialog, int which) {  
  63.                     List<Overlay> overlays = map.getOverlays();  
  64.                     GeoPoint gpoint = new GeoPoint((int)lat,(int)lon);  
  65.                     OverlayItem overlayitem = new OverlayItem(gpoint, "title""content");  
  66.                     Drawable drawale = context.getResources().getDrawable(R.drawable.current_mark);  
  67.                     MyItemizedOverlay iconOverlay = new MyItemizedOverlay(context,drawale);  
  68.                     // 添加图层   
  69.                     iconOverlay.addOverlay(overlayitem);  
  70.                     overlays.add(iconOverlay);  
  71.                     map.getController().animateTo(gpoint);  
  72.                       
  73.                     Editor editor = sharedPreferences.edit();  
  74.                     editor.putFloat("lat", lat);  
  75.                     editor.putFloat("lon", lon);  
  76.                     editor.commit();  
  77.                     Toast.makeText(context, "纬度:"+lat / 1E6+"\n经度:"+lon / 1E6, Toast.LENGTH_SHORT).show();    
  78.                 }  
  79.             });  
  80.             builder.setNegativeButton("取消"null);  
  81.             builder.create().show();  
  82.         }else {  
  83. //          AlertDialog.Builder builder = new AlertDialog.Builder(this.context);   
  84. //          builder.setTitle("设置目的地");   
  85. //          builder.setMessage("已经设置过线路,请先点击清除路线按钮清除当前路线");   
  86. //          builder.setNegativeButton("确定", null);   
  87. //          builder.create().show();   
  88.             Toast.makeText(context, "已经设置过线路,请先点击清除路线按钮清除当前路线",Toast.LENGTH_SHORT).show();    
  89.               
  90.         }  
  91.           
  92.         return super.onTap(p, mapView);  
  93.     }     
  94. }  

最后是主Activity实现类,注释中有详细说明:

[java] view plain copy print ?
  1. public class NavigationDemoActivity extends MapActivity {  
  2.     //Map key   
  3.     private String mMapKey = "你的MapKey,到百度开发者官网申请";  
  4.       
  5.     private EditText destinationEditText = null;  
  6.     private Button startNaviButton = null;  
  7.     private Button clearButton = null;  
  8.     private MapView mapView = null;  
  9.     private BMapManager mMapManager = null;  
  10.     private MyLocationOverlay myLocationOverlay = null;  
  11.     //onResume时注册此listener,onPause时需要Remove,注意此listener不是Android自带的,是百度API中的   
  12.     private LocationListener locationListener = null;  
  13.     //搜索模块   
  14.     private MKSearch searchModel = null;  
  15.     private GeoPoint pt = null;  
  16.     private SharedPreferences sharedPreferences;  
  17.       
  18.     @Override  
  19.     public void onCreate(Bundle savedInstanceState) {  
  20.         super.onCreate(savedInstanceState);  
  21.         requestWindowFeature(Window.FEATURE_NO_TITLE);  
  22.         setContentView(R.layout.main);  
  23.         //弹出使用说明对话框   
  24.         showIntroduceDialog();  
  25.           
  26.         sharedPreferences = this.getSharedPreferences("navigation_pre", Context.MODE_WORLD_WRITEABLE);  
  27.         destinationEditText = (EditText) this.findViewById(R.id.et_destination);  
  28.         startNaviButton = (Button) this.findViewById(R.id.btn_navi);  
  29.         clearButton = (Button) this.findViewById(R.id.btn_clear);  
  30.           
  31.         //初始化地图管理器   
  32.         mMapManager = new BMapManager(getApplication());  
  33.         mMapManager.init(mMapKey, new MyGeneralListener());  
  34.         super.initMapActivity(mMapManager);  
  35.           
  36.         mapView = (MapView) this.findViewById(R.id.bmapsView);  
  37.         //设置启用内置的缩放控件   
  38.         mapView.setBuiltInZoomControls(true);    
  39.         //设置在缩放动画过程中也显示overlay,默认为不绘制   
  40. //        mapView.setDrawOverlayWhenZooming(true);   
  41.         //设置初始化地图的缩放级别   
  42.         mapView.getController().setZoom(16);  
  43.         mapView.setClickable(true);  
  44.           
  45.         //获取当前位置层   
  46.         myLocationOverlay = new MyLocationOverlay(this, mapView);  
  47.         //将当前位置的层添加到地图底层中   
  48.         mapView.getOverlays().add(myLocationOverlay);  
  49.           
  50.         //添加可点选地图获取目的地的层   
  51.         addTapOverLay();  
  52.           
  53.         //注册定位事件   
  54.         locationListener = new LocationListener(){  
  55.   
  56.             @Override  
  57.             public void onLocationChanged(Location location) {  
  58.                 if (location != null){  
  59.                     //生成GEO类型坐标并在地图上定位到该坐标标示的地点   
  60.                      pt = new GeoPoint((int)(location.getLatitude() * 1e6),  
  61.                             (int)(location.getLongitude() * 1e6));  
  62.                      mapView.getController().animateTo(pt);  
  63.                 }  
  64.             }  
  65.         };  
  66.           
  67.         //初始化搜索模块   
  68.         searchModel = new MKSearch();  
  69.         //设置路线策略为最短距离   
  70.         searchModel.setDrivingPolicy(MKSearch.ECAR_DIS_FIRST);  
  71.         searchModel.init(mMapManager, new MKSearchListener() {  
  72.             //获取驾车路线回调方法   
  73.             @Override  
  74.             public void onGetDrivingRouteResult(MKDrivingRouteResult res, int error) {  
  75.                 // 错误号可参考MKEvent中的定义   
  76.                 if (error != 0 || res == null) {  
  77.                     Toast.makeText(NavigationDemoActivity.this"抱歉,未找到结果", Toast.LENGTH_SHORT).show();  
  78.                     return;  
  79.                 }  
  80.                 RouteOverlay routeOverlay = new RouteOverlay(NavigationDemoActivity.this, mapView);  
  81.                   
  82.                 // 此处仅展示一个方案作为示例   
  83.                 MKRoute route = res.getPlan(0).getRoute(0);  
  84.                 int distanceM = route.getDistance();  
  85.                 String distanceKm = String.valueOf(distanceM / 1000) +"."+String.valueOf(distanceM % 1000);  
  86.                 System.out.println("距离:"+distanceKm+"公里---节点数量:"+route.getNumSteps());  
  87.                 for (int i = 0; i < route.getNumSteps(); i++) {  
  88.                     MKStep step = route.getStep(i);  
  89.                     System.out.println("节点信息:"+step.getContent());  
  90.                     System.out.println("经度:"+step.getPoint().getLongitudeE6() / 1E6 +" 纬度:"+step.getPoint().getLatitudeE6() / 1E6);  
  91.                 }  
  92.                 routeOverlay.setData(route);  
  93.                 mapView.getOverlays().clear();  
  94.                 mapView.getOverlays().add(routeOverlay);  
  95.                 mapView.invalidate();  
  96.                 mapView.getController().animateTo(res.getStart().pt);  
  97.             }  
  98.               
  99.             //以下两种方式和上面的驾车方案实现方法一样   
  100.             @Override  
  101.             public void onGetWalkingRouteResult(MKWalkingRouteResult res, int error) {  
  102.                 //获取步行路线   
  103.             }  
  104.               
  105.             @Override  
  106.             public void onGetTransitRouteResult(MKTransitRouteResult arg0, int arg1) {  
  107.                 //获取公交线路   
  108.             }  
  109.               
  110.             @Override  
  111.             public void onGetBusDetailResult(MKBusLineResult arg0, int arg1) {  
  112.             }  
  113.             @Override  
  114.             public void onGetAddrResult(MKAddrInfo arg0, int arg1) {  
  115.             }  
  116.             @Override  
  117.             public void onGetSuggestionResult(MKSuggestionResult arg0, int arg1) {  
  118.             }  
  119.             @Override  
  120.             public void onGetPoiResult(MKPoiResult arg0, int arg1, int arg2) {  
  121.             }  
  122.         });  
  123.           
  124.         startNaviButton.setOnClickListener(new OnClickListener() {  
  125.               
  126.             @Override  
  127.             public void onClick(View v) {  
  128.                 String destination = destinationEditText.getText().toString();  
  129.                   
  130.                 //设置起始地(当前位置)   
  131.                 MKPlanNode startNode = new MKPlanNode();  
  132.                 startNode.pt = pt;  
  133.                   
  134.                 //设置目的地   
  135.                 MKPlanNode endNode = new MKPlanNode();   
  136.                   
  137.                 float lat = sharedPreferences.getFloat("lat"0);  
  138.                 float lon = sharedPreferences.getFloat("lon"0);  
  139.                   
  140.                 if (lat != 0 && lon != 0) {  
  141.                     endNode.pt = new GeoPoint((int)lat,(int)lon);  
  142.                 }else if (!destination.equals("")) {  
  143.                     endNode.name = destination;  
  144.                 }else {  
  145.                     Toast.makeText(NavigationDemoActivity.this"请输入或点选目的地",Toast.LENGTH_SHORT).show();  
  146.                     return;  
  147.                 }  
  148.                   
  149.                 //展开搜索的城市   
  150.                 String city = getResources().getString(R.string.beijing);  
  151.                 searchModel.drivingSearch(city, startNode, city, endNode);  
  152.                   
  153.                 //步行路线   
  154. //              searchModel.walkingSearch(city, startNode, city, endNode);   
  155.                 //公交路线   
  156. //              searchModel.transitSearch(city, startNode, endNode);   
  157.             }  
  158.         });  
  159.           
  160.         //清除路线按钮事件   
  161.         clearButton.setOnClickListener(new OnClickListener() {  
  162.               
  163.             @Override  
  164.             public void onClick(View v) {  
  165.                 List<Overlay> overlays = mapView.getOverlays();  
  166.                   
  167.                 if (sharedPreferences.getFloat("lon"0) != 0) {  
  168.                     //移除顶层的路线图层   
  169.                     overlays.remove(overlays.size() - 1);  
  170.                     //添加用户当前位置图层   
  171.                     overlays.add(myLocationOverlay);  
  172.                     //地图更新定位到当前位置   
  173.                     mapView.getController().animateTo(pt);  
  174.                       
  175.                     //清除存储的经纬度信息   
  176.                     Editor editor = sharedPreferences.edit();  
  177.                     editor.clear();  
  178.                     editor.commit();  
  179.                       
  180.                     //添加可点选图层   
  181.                     addTapOverLay();  
  182.                       
  183.                 }else if (!destinationEditText.getText().toString().equals("")) {  
  184.                     overlays.remove(overlays.size() - 1);  
  185.                     overlays.add(myLocationOverlay);  
  186.                     mapView.getController().animateTo(pt);  
  187.                     addTapOverLay();  
  188.                 }else {  
  189.                     Toast.makeText(NavigationDemoActivity.this"没有设置路线", Toast.LENGTH_SHORT).show();  
  190.                 }  
  191.             }  
  192.         });  
  193.     }  
  194.       
  195.     public void showIntroduceDialog(){  
  196.         AlertDialog.Builder builder = new AlertDialog.Builder(this);  
  197.         builder.setTitle("使用说明");  
  198.         StringBuilder sb = new StringBuilder();  
  199.         sb.append("1.地图中蓝色点为当前位置;\n\n");  
  200.         sb.append("2.双指捏合或点击缩放按钮可以缩放地图;\n\n");  
  201.         sb.append("3.在输入框中输入目的地或在地图上点选目的地;\n\n");  
  202.         sb.append("4.选取目的地后点击按钮开始导航;\n\n");  
  203.         sb.append("5.点击清除按钮取消本次导航路线;");  
  204.         builder.setMessage(sb.toString());  
  205.         builder.setNegativeButton("确定"null);  
  206.         builder.create().show();  
  207.     }  
  208.       
  209.     public void addTapOverLay(){  
  210.         //以一副透明图片标示可点选图层,这里在地图上不显示出来,只提供可点选目的地功能   
  211.         GeoPoint gpoint = new GeoPoint((int) (39.914714 * 1E6), (int) (116.404269 * 1E6));  
  212.         OverlayItem overlayitem = new OverlayItem(gpoint, "title""content");  
  213.         Drawable drawale = getResources().getDrawable(R.drawable.current);  
  214.         MyItemizedOverlay iconOverlay = new MyItemizedOverlay(NavigationDemoActivity.this,drawale);  
  215.         // 添加图层   
  216.         iconOverlay.addOverlay(overlayitem);  
  217.         mapView.getOverlays().add(iconOverlay);  
  218.     }  
  219.       
  220.     @Override  
  221.     protected void onResume() {  
  222.         mMapManager.getLocationManager().requestLocationUpdates(locationListener);  
  223.         myLocationOverlay.enableMyLocation();  
  224.         myLocationOverlay.enableCompass(); // 打开指南针   
  225.         mMapManager.start();  
  226.           
  227.         super.onResume();  
  228.     }  
  229.       
  230.     @Override  
  231.     protected void onPause() {  
  232.         mMapManager.getLocationManager().removeUpdates(locationListener);  
  233.         myLocationOverlay.disableMyLocation();//显示当前位置   
  234.         myLocationOverlay.disableCompass(); // 关闭指南针   
  235.         mMapManager.stop();  
  236.         super.onPause();  
  237.     }  
  238.   
  239.     @Override  
  240.     protected boolean isRouteDisplayed() {  
  241.         // TODO Auto-generated method stub   
  242.         return false;  
  243.     }  
  244.       
  245.     //按物理返回键退出应用时清空存储的经纬度信息   
  246.     @Override  
  247.     public boolean dispatchKeyEvent(KeyEvent event) {  
  248.         if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {  
  249.             Editor editor = sharedPreferences.edit();  
  250.             editor.clear();  
  251.             editor.commit();  
  252.         }  
  253.         return super.dispatchKeyEvent(event);  
  254.     }  
  255.       
  256.     // 常用事件监听,用来处理通常的网络错误,授权验证错误等   
  257.     class MyGeneralListener implements MKGeneralListener {  
  258.             @Override  
  259.             public void onGetNetworkState(int iError) {  
  260.                 Log.d("MyGeneralListener""onGetNetworkState error is "+ iError);  
  261.                 Toast.makeText(NavigationDemoActivity.this"您的网络出错啦!",  
  262.                         Toast.LENGTH_LONG).show();  
  263.             }  
  264.   
  265.             @Override  
  266.             public void onGetPermissionState(int iError) {  
  267.                 Log.d("MyGeneralListener""onGetPermissionState error is "+ iError);  
  268.                 if (iError ==  MKEvent.ERROR_PERMISSION_DENIED) {  
  269.                     // 授权Key错误:   
  270.                     Toast.makeText(NavigationDemoActivity.this,   
  271.                             "请在BMapApiDemoApp.java文件输入正确的授权Key!",  
  272.                             Toast.LENGTH_LONG).show();  
  273.                 }  
  274.             }  
  275.         }  
  276. }  

最后是配置文件:

[html] view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.ericssonlabs"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk android:minSdkVersion="8" />  
  8.   
  9.     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>  
  10.     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>  
  11.     <uses-permission android:name="android.permission.INTERNET"></uses-permission>  
  12.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>  
  13.     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>    
  14.     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>   
  15.     <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>  
  16.       
  17.     <supports-screens android:largeScreens="true"  
  18.         android:normalScreens="true" android:smallScreens="true"  
  19.         android:resizeable="true" android:anyDensity="true"/>  
  20.     <uses-sdk android:minSdkVersion="3"></uses-sdk>  
  21.   
  22.     <application  
  23.         android:icon="@drawable/ic_launcher"  
  24.         android:label="@string/app_name" >  
  25.         <activity  
  26.             android:name=".NavigationDemoActivity"  
  27.             android:label="@string/app_name" >  
  28.             <intent-filter>  
  29.                 <action android:name="android.intent.action.MAIN" />  
  30.   
  31.                 <category android:name="android.intent.category.LAUNCHER" />  
  32.             </intent-filter>  
  33.         </activity>  
  34.     </application>  
  35.   
  36. </manifest>  


你可能感兴趣的:(使用百度地图API实现驾车导航)