根据我对地图的开发经验,MapView+定位+覆盖物+路线搜索,这四个模块基本上已经可以满足开发需求了。百度地图官网下载的BaiduMapsApiDemo使用发杂,移植性又不好。我对这四个模块功能做了一个总的封装,使用起来更加简便。
使用如下:
1、初始化地图
在XML布局中只需要调用
在activity中
BaiduMapView baiduMapView = (BaiduMapView) findViewById(R.id.baidumapview);
2、定位。定位已经是完全独立的模块了,具体实现参考《Android百度地图——定位》
//定位
BaiduLocation.getLocation(context);
BaiduLocation.setMyLocationListener(new BaiduLocation.MyLocationListener(){
@Override
public void myLocatin(double mylongitude, double mylatitude, String city, String street) {
// TODO Auto-generated method stub
baiduMapView.setCenter(new LatLng(mylatitude,mylongitude) );
}
});
3、覆盖物
添加覆盖物只需一行代码,设置参数view,经纬度,覆盖物的title(用于标识)
baiduMapView.addOverlay(View.inflate(getApplicationContext(), R.layout.view_baidumap, null)
, new LatLng(BaiduLocation.mylatitude, BaiduLocation.mylongitude), "title");
覆盖物点击事件
baiduMapView.setOnMarkerClickListener(new OnMyMarkerClickListener() {
@Override
public void onMarkerClick(Marker arg0) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), ""+arg0.getTitle(), 0).show();
}
});
4、路线搜索。搜索结果会自动在地图上加载
ArrayList pass=new ArrayList();
pass.add(new LatLng( 23.102603,113.304713));
baiduMapView.SearchProcess(new LatLng( 23.159499,113.261269)
, new LatLng(23.15312,113.328859 )
, pass
, BaiduSearch.DrivingRoute);
说那么多来看一下效果图
下面附上各文件的源代码
除了上面几个类,还必须要如下文件,这些都是BaiduMapsApiDemo中的原文件,不需要修改直接copy。
再强调使用百度地图需要配置好的几点:
1、权限
2、定位需要的服务
3、API_KEY,去百度地图API官网申请该应用的key
4、activity中初始化百度地图,在setContentView前面加入SDKInitializer.initialize(getApplicationContext());
super.onCreate(savedInstanceState);
SDKInitializer.initialize(getApplicationContext());
setContentView(R.layout.activity_baidumap_test);
5、在测试的时候需要通过Export导出项目app安装包,把程序安装到手机上测试,不能直接通过开发工具debug程序到手机中测试。原因是因为申请的API_KEY是由程序的包名和keystore通过sha1加密生成的,程序必须Export导出项目通过keystone签名加密才能匹配到API_KEY。
BaiduLocation.java:
package baidumap;
import android.content.Context;
import android.util.Log;
import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
public class BaiduLocation {
/**经度*/
public static double mylongitude = -1.0;
/**纬度*/
public static double mylatitude = -1.0;
/**城市*/
public static String myCity = null;
/**街道*/
public static String myCityadd = null;
/**
* 回调经纬度方法
* @param myLocationListener
*/
public static void setMyLocationListener(MyLocationListener myLocationListener) {
BaiduLocation.myLocationListener = myLocationListener;
}
public static MyLocationListener myLocationListener;
/**
* 回调经纬度的接口定义
* @author Administrator
*/
public static interface MyLocationListener {
public void myLocatin(double mylongitude, double mylatitude, String city, String street);
};
/**
* 获取当前经纬度
* @param activity
*/
public static void getLocation(Context context) {
final LocationClient locationClient = new LocationClient(context);
// 设置定位条件
LocationClientOption option = new LocationClientOption();
option.setOpenGps(true); // 是否打开GPS
option.setCoorType("bd09ll"); // 设置返回值的坐标类型。
option.setPriority(LocationClientOption.NetWorkFirst); // 设置定位优先级
option.setProdName("zhongchengbus"); // 设置产品线名称。强烈建议您使用自定义的产品线名称,方便我们以后为您提供更高效准确的定位服务。
option.setScanSpan(5000); // 设置定时定位的时间间隔。单位毫秒
option.setAddrType("all");// 显示所有信息,街道
locationClient.setLocOption(option);
// 注册位置监听器
locationClient.registerLocationListener(new BDLocationListener() {
@Override
public void onReceiveLocation(BDLocation location) {
// TODO Auto-generated method stub
if (location == null) {
return;
}
Log.d("baidulocation", "baidulocation1");
// sb.append("Time : ");
// sb.append(location.getTime());
// sb.append("\nError code : ");
// sb.append(location.getLocType());
// sb.append("\nLatitude : ");
// sb.append(location.getLatitude());
// sb.append("\nLontitude : ");
// sb.append(location.getLongitude());
// sb.append("\nRadius : ");
// sb.append(location.getRadius());
// if (location.getLocType() == BDLocation.TypeGpsLocation){
// sb.append("\nSpeed : ");
// sb.append(location.getSpeed());
// sb.append("\nSatellite : ");
// sb.append(location.getSatelliteNumber());
// } else
if (location.getLocType() == BDLocation.TypeNetWorkLocation) {
// sb.append("\nAddress : ");
// sb.append(location.getAddrStr());
String district = location.getAddress().district;
myCityadd = location.getAddrStr();
myCity = location.getCity();
mylongitude = location.getLongitude();
mylatitude = location.getLatitude();
Log.d("baidulocation", mylongitude+"\n"+mylatitude+"\n"+ myCity+"\n"+district);
// 经纬度
if (myLocationListener != null) {
myLocationListener.myLocatin(mylongitude, mylatitude, myCity, district);
locationClient.stop();
}
}
}
});
locationClient.start();
/*
* 当所设的整数值大于等于1000(ms)时,定位SDK内部使用定时定位模式。调用requestLocation(
* )后,每隔设定的时间,定位SDK就会进行一次定位。如果定位SDK根据定位依据发现位置没有发生变化,就不会发起网络请求,
* 返回上一次定位的结果;如果发现位置改变,就进行网络请求进行定位,得到新的定位结果。
* 定时定位时,调用一次requestLocation,会定时监听到定位结果。
*/
locationClient.requestLocation();
Log.d("baidulocation", "baidulocation");
}
}
BaiduMapView.java
package baidumap;
import java.util.ArrayList;
import java.util.HashMap;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.MapPoi;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.Marker;
import com.baidu.mapapi.map.MarkerOptions;
import com.baidu.mapapi.map.BaiduMap.OnMarkerClickListener;
import com.baidu.mapapi.map.MarkerOptions.MarkerAnimateType;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.overlayutil.DrivingRouteOverlay;
import com.baidu.mapapi.overlayutil.TransitRouteOverlay;
import com.baidu.mapapi.overlayutil.WalkingRouteOverlay;
import com.baidu.mapapi.search.route.BikingRouteResult;
import com.baidu.mapapi.search.route.DrivingRouteResult;
import com.baidu.mapapi.search.route.TransitRouteResult;
import com.baidu.mapapi.search.route.WalkingRouteResult;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import baidumap.BaiduSearch.OnMyGetRoutePlanResultListener;
public class BaiduMapView extends LinearLayout implements BaiduMap.OnMapClickListener{
private Context context;
//地图相关,使用继承MapView的MyRouteMapView目的是重写touch事件实现泡泡处理
//如果不处理touch事件,则无需继承,直接使用MapView即可
/**地图View */
private MapView mMapView = null;
private BaiduMap mBaidumap = null;
//覆盖物相关
private HashMap markers=new HashMap();//保存覆盖物
/** 覆盖物点击接口 */
public interface OnMyMarkerClickListener{
public void onMarkerClick(Marker arg0);
}
private OnMyMarkerClickListener listener=null;
public void setOnMarkerClickListener(OnMyMarkerClickListener listener){
this.listener=listener;
}
public BaiduMapView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
this.context=context;
initBaiduMap();
}
/**初始化百度地图
*
*/
private void initBaiduMap(){
Log.v("BaiduMapView", "initBaiduMap");
//初始化地图
mMapView =new MapView(context);
mMapView.showZoomControls(false);//缩放按钮
mBaidumap = mMapView.getMap();
//地图点击事件处理
mBaidumap.setOnMapClickListener(this);
// mBaidumap.setOnMapLoadedCallback(new OnMapLoadedCallback() {
//
// @Override
// public void onMapLoaded() {
// // TODO Auto-generated method stub
// ToastUtils.showTextToast(SelectStationActivity.this, "地图加载完成");
//
// //SearchButtonProcess();
// }
// });
//定位
BaiduLocation.getLocation(context);
BaiduLocation.setMyLocationListener(new BaiduLocation.MyLocationListener(){
@Override
public void myLocatin(double mylongitude, double mylatitude, String city, String street) {
// TODO Auto-generated method stub
setCenter(new LatLng(mylatitude,mylongitude) );
}
});
addView(mMapView);
}
/**设置中心点
* @param latLng
*/
public void setCenter(LatLng latLng){
MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(latLng);
mBaidumap.animateMapStatus(u);
}
@Override
public void onMapClick(LatLng arg0) {
// TODO Auto-generated method stub
mBaidumap.hideInfoWindow();
}
@Override
public boolean onMapPoiClick(MapPoi arg0) {
// TODO Auto-generated method stub
return false;
}
/**添加覆盖物
* @param view
* @param ll 经纬度坐标
* @param title 覆盖物title,用于标识
*/
public void addOverlay(View view,LatLng ll,String title) {
// add marker overlay
BitmapDescriptor bdC = BitmapDescriptorFactory.fromView(view);
MarkerOptions ooC = new MarkerOptions().title(title).position(ll).icon(bdC).perspective(false).anchor(0.5f, 1f);
ooC.animateType(MarkerAnimateType.grow);//生长动画
markers.put(title,(Marker)(mBaidumap.addOverlay(ooC)));//此处可以强转成Marker,控制覆盖物移动
mBaidumap.setOnMarkerClickListener(new OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker arg0) {
// TODO Auto-generated method stub
if (listener!=null) {
listener.onMarkerClick(arg0);
}
return true;
}
});
}
/**设置覆盖物位置
* @param ll 经纬度坐标
*/
public void setOverlayLatLng(String title,LatLng ll){
if (markers!=null) {
Marker marker = markers.get(title);
if (marker!=null) {
marker.setPosition(ll);
}
}
}
/**发起路线规划搜索示例
* @param start 起点
* @param end 终点
* @param passBy 途经点,仅在drivingSearch有效
* @param state 选择搜索方式
*/
public void SearchProcess(LatLng start,LatLng end,ArrayList passBy,int state) {
BaiduSearch search = new BaiduSearch(context);
search.setOnMyGetRoutePlanResultListener(new OnMyGetRoutePlanResultListener() {
@Override
public void onGetWalkingRouteResult(WalkingRouteResult arg0) {
// TODO Auto-generated method stub
WalkingRouteOverlay overlay = new WalkingRouteOverlay(mBaidumap);
// mBaidumap.setOnMarkerClickListener(overlay);
overlay.setData(arg0.getRouteLines().get(0));
overlay.addToMap();
overlay.zoomToSpan();
}
@Override
public void onGetTransitRouteResult(TransitRouteResult arg0) {
// TODO Auto-generated method stub
TransitRouteOverlay overlay = new TransitRouteOverlay(mBaidumap);
// mBaidumap.setOnMarkerClickListener(overlay);
overlay.setData(arg0.getRouteLines().get(0));
overlay.addToMap();
overlay.zoomToSpan();
}
@Override
public void onGetDrivingRouteResult(DrivingRouteResult arg0) {
// TODO Auto-generated method stub
DrivingRouteOverlay overlay = new MyDrivingRouteOverlay(mBaidumap);
// mBaidumap.setOnMarkerClickListener(overlay);
overlay.setData(arg0.getRouteLines().get(0));
overlay.addToMap();
overlay.zoomToSpan();
}
@Override
public void onGetBikingRouteResult(BikingRouteResult arg0) {
// TODO Auto-generated method stub
}
});
search.SearchProcess(start, end, passBy, state);
}
/**
* 设置底图显示模式
*
* @param state 0:普通图 1:卫星图
*/
public void setMapMode(int state) {
switch (state) {
case 0:
mBaidumap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
break;
case 1:
mBaidumap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
break;
default:
break;
}
}
/**
* 设置是否显示交通图
*
* @param isTraffic
*/
public void setTraffic(boolean isTraffic) {
mBaidumap.setTrafficEnabled(isTraffic);
}
/**
* 设置是否显示百度热力图
*
* @param isHeatMap
*/
public void setBaiduHeatMap(boolean isHeatMap) {
mBaidumap.setBaiduHeatMapEnabled(isHeatMap);
}
}
BaiduSearch.java
package baidumap;
import java.util.ArrayList;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.search.core.SearchResult;
import com.baidu.mapapi.search.route.BikingRoutePlanOption;
import com.baidu.mapapi.search.route.BikingRouteResult;
import com.baidu.mapapi.search.route.DrivingRoutePlanOption;
import com.baidu.mapapi.search.route.DrivingRouteResult;
import com.baidu.mapapi.search.route.OnGetRoutePlanResultListener;
import com.baidu.mapapi.search.route.PlanNode;
import com.baidu.mapapi.search.route.RoutePlanSearch;
import com.baidu.mapapi.search.route.TransitRoutePlanOption;
import com.baidu.mapapi.search.route.TransitRouteResult;
import com.baidu.mapapi.search.route.WalkingRoutePlanOption;
import com.baidu.mapapi.search.route.WalkingRouteResult;
import android.content.Context;
import android.widget.Toast;
/**
* @author 王家宇
*
*/
public class BaiduSearch implements OnGetRoutePlanResultListener{
private Context context;
private RoutePlanSearch mSearch = null; // 搜索模块,也可去掉地图模块独立使用
/** 路径规划接口 */
public interface OnMyGetRoutePlanResultListener{
public void onGetBikingRouteResult(BikingRouteResult arg0);
public void onGetDrivingRouteResult(DrivingRouteResult arg0);
public void onGetTransitRouteResult(TransitRouteResult arg0) ;
public void onGetWalkingRouteResult(WalkingRouteResult arg0);
}
private OnMyGetRoutePlanResultListener listener=null;
public void setOnMyGetRoutePlanResultListener(OnMyGetRoutePlanResultListener listener){
this.listener=listener;
}
/** 自行车 */
public static final int BikingRoute=0;
/** 驾车 */
public static final int DrivingRoute=1;
/** 公交 */
public static final int TransitRoute=2;
/** 步行 */
public static final int WalkingRoute=3;
public BaiduSearch(Context context){
this.context=context;
// 初始化搜索模块,注册事件监听
mSearch = RoutePlanSearch.newInstance();
mSearch.setOnGetRoutePlanResultListener(this);
}
/**发起路线规划搜索示例
* @param start 起点
* @param end 终点
* @param passBy 途经点,仅在drivingSearch有效
* @param state 选择搜索方式
*/
public void SearchProcess(LatLng start,LatLng end,ArrayList passBy,int state) {
ArrayList arg0 =new ArrayList();
//设置起终点信息,对于tranistsearch 来说,城市名无意义
PlanNode stNode = PlanNode.withLocation(start);
PlanNode enNode = PlanNode.withLocation(end);
if (passBy!=null) {
for (int i = 0; i < passBy.size(); i++) {
PlanNode node = PlanNode.withLocation(passBy.get(i));
arg0.add(node);
}
}
// 实际使用中请对起点终点城市进行正确的设定
switch (state) {
case BikingRoute:
mSearch.bikingSearch((new BikingRoutePlanOption())
.from(stNode)
.to(enNode));
break;
case DrivingRoute:
mSearch.drivingSearch((new DrivingRoutePlanOption())
.from(stNode)
.passBy(arg0)
.to(enNode));
break;
case TransitRoute:
mSearch.transitSearch((new TransitRoutePlanOption())
.from(stNode)
.to(enNode));
break;
case WalkingRoute:
mSearch.walkingSearch((new WalkingRoutePlanOption())
.from(stNode)
.to(enNode));
break;
default:
break;
}
}
@Override
public void onGetDrivingRouteResult(DrivingRouteResult result) {
// TODO Auto-generated method stub
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
Toast.makeText(context, "抱歉,未找到结果", Toast.LENGTH_SHORT).show();
}
if (result.error == SearchResult.ERRORNO.AMBIGUOUS_ROURE_ADDR) {
//起终点或途经点地址有岐义,通过以下接口获取建议查询信息
//result.getSuggestAddrInfo()
Toast.makeText(context, "抱歉,未找到结果", Toast.LENGTH_SHORT).show();
return;
}
if (result.error == SearchResult.ERRORNO.NO_ERROR) {
if (listener!=null) {
listener.onGetDrivingRouteResult(result);
}
}
}
@Override
public void onGetBikingRouteResult(BikingRouteResult result) {
// TODO Auto-generated method stub
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
Toast.makeText(context, "抱歉,未找到结果", Toast.LENGTH_SHORT).show();
}
if (result.error == SearchResult.ERRORNO.AMBIGUOUS_ROURE_ADDR) {
//起终点或途经点地址有岐义,通过以下接口获取建议查询信息
//result.getSuggestAddrInfo()
Toast.makeText(context, "抱歉,未找到结果", Toast.LENGTH_SHORT).show();
return;
}
if (result.error == SearchResult.ERRORNO.NO_ERROR) {
if (listener!=null) {
listener.onGetBikingRouteResult(result);
}
}
}
@Override
public void onGetTransitRouteResult(TransitRouteResult result) {
// TODO Auto-generated method stub
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
Toast.makeText(context, "抱歉,未找到结果", Toast.LENGTH_SHORT).show();
}
if (result.error == SearchResult.ERRORNO.AMBIGUOUS_ROURE_ADDR) {
//起终点或途经点地址有岐义,通过以下接口获取建议查询信息
//result.getSuggestAddrInfo()
Toast.makeText(context, "抱歉,未找到结果", Toast.LENGTH_SHORT).show();
return;
}
if (result.error == SearchResult.ERRORNO.NO_ERROR) {
if (listener!=null) {
listener.onGetTransitRouteResult(result);
}
}
}
@Override
public void onGetWalkingRouteResult(WalkingRouteResult result) {
// TODO Auto-generated method stub
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
Toast.makeText(context, "抱歉,未找到结果", Toast.LENGTH_SHORT).show();
}
if (result.error == SearchResult.ERRORNO.AMBIGUOUS_ROURE_ADDR) {
//起终点或途经点地址有岐义,通过以下接口获取建议查询信息
//result.getSuggestAddrInfo()
Toast.makeText(context, "抱歉,未找到结果", Toast.LENGTH_SHORT).show();
return;
}
if (result.error == SearchResult.ERRORNO.NO_ERROR) {
if (listener!=null) {
listener.onGetWalkingRouteResult(result);
}
}
}
}
MyDrivingRouteOverlay.java
package baidumap;
import java.util.ArrayList;
import java.util.List;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.overlayutil.DrivingRouteOverlay;
import android.view.View;
public class MyDrivingRouteOverlay extends DrivingRouteOverlay {
private boolean useDefaultIcon = false;//自定义图标
private View startView;
private View endView;
private ArrayList passView;
public MyDrivingRouteOverlay(BaiduMap baiduMap) {
super(baiduMap);
}
public MyDrivingRouteOverlay(BaiduMap baiduMap,View startView,View endView,ArrayList passView) {
super(baiduMap);
useDefaultIcon = true;
this.startView=startView;
this.endView=endView;
this.passView=passView;
}
@Override
public BitmapDescriptor getStartMarker() {
if (useDefaultIcon) {
if (startView==null) {
return null;
}
BitmapDescriptor bd = BitmapDescriptorFactory.fromView(startView);
return bd;
}
return null;
}
@Override
public List getCustomTextureList() {
// TODO Auto-generated method stub
if (useDefaultIcon) {
if (passView==null) {
return null;
}
ArrayList list = new ArrayList();
for (int i = 0; i < passView.size(); i++) {
list.add(BitmapDescriptorFactory.fromView(passView.get(i)));
}
return list;
}
return null;
}
@Override
public int getLineColor() {
// TODO Auto-generated method stub
//覆写此方法以改变默认绘制颜色
//Returns:
//线颜色
return super.getLineColor();
}
@Override
public BitmapDescriptor getTerminalMarker() {
if (useDefaultIcon) {
if (endView==null) {
return null;
}
BitmapDescriptor bd = BitmapDescriptorFactory.fromView(endView);
return bd;
}
return null;
}
@Override
public boolean onRouteNodeClick(int i) {
// TODO Auto-generated method stub
System.out.println(""+i);
return true;
}
}