官方文档:
百度地图SDK为开发人员们提供了例如以下类型的地图覆盖物:
-
我的位置图层(MyLocationOverlay):用于显示用户当前位置的图层(支持自己定义位置图标);
-
Poi搜索结果图层(PoiOverlay):用于显示兴趣点搜索结果的图层;
-
路线图层(RouteOverlay):公交、步行和驾车线路图层,将公交、步行和驾车出行方案的路线及关键点显示在地图上(起、终点图标用户可自己定义);
-
公交换乘图层(TransitOverlay):公交换乘线路图层,将某一特定地区的公交出行方案的路线及换乘位置显示在地图上(起、终点图标用户可自己定义);
-
自己定义图层(ItemizedOverlay):可将一个或多个兴趣点绘制到地图上,且支持自己定义图标(支持动态更新Item位置、图标);
-
弹出窗图层(PopupOverlay):在地图上显示一个弹出窗体;
-
几何图形绘制图层(GraphicsOverlay):用于绘制点、折线段、弧线、圆、矩形、多边形等几何图形的图层;
-
文字绘制图层(TextOverlay):用于绘制文字的图层。
-
图片图层(GroundOverlay):用于展示用户传入图片的图层。
-
全景图图层(PanoramaOverlay):在全景图内标绘兴趣点,支持自己定义图标样式。
注:除弹出窗图层外,其它各个图层均已实现多实例。全景图图层是针对全景图所使用的特殊图层。
MapView使用一个List管理覆盖物,通过向MapView.getOverlays() add或remove上述类或其基类的实例就可以向地图加入或删除覆盖物。在更新地图覆盖物后,需调用MapView.refresh() 使更新生效。
定位原理
使用百度Android定位SDK必须注冊GPS和网络使用权限。定位SDK採用GPS、基站、Wi-Fi信号进行定位。当应用程序向定位SDK发起定位请求时,定位SDK会根据应用的定位因素(GPS、基站、Wi-Fi信号)的实际情况(如是否开启GPS、是否连接网络、是否有信号等)来生成对应定位根据进行定位。 用户能够设置满足自身需求的定位根据: 若用户设置GPS优先,则优先使用GPS进行定位,假设GPS定位未打开或者没有可用位置信息,且网络连接正常,定位SDK则会返回网络定位(即Wi-Fi与基站)的最优结果。为了使获得的网络定位结果更加精确,请打开手机的Wi-Fi开关。
以下我们将利用 MyLocationOverlay和 PopupOverlay 这两个类
一 . 导入库文件
在使用百度定位SDKv4.0之前,我们要下载最新的库文件,下载地址:,将liblocSDK4.so文件复制到libs/armeabi文件夹下。将locSDK4.0.jar文件复制到project的libs文件夹下
文件夹结构例如以下:
库文件下载地址:
二 . 布局文件,一个百度地图控件,加一个手动点击实现定位的button
然后是主 Activity
package com.majianjie.baidumap;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.view.LayoutInflater;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.View.MeasureSpec;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;import com.baidu.location.BDLocation;import com.baidu.location.BDLocationListener;import com.baidu.location.LocationClient;import com.baidu.location.LocationClientOption;import com.baidu.mapapi.BMapManager;import com.baidu.mapapi.MKGeneralListener;import com.baidu.mapapi.map.LocationData;import com.baidu.mapapi.map.MKEvent;import com.baidu.mapapi.map.MKMapViewListener;import com.baidu.mapapi.map.MapController;import com.baidu.mapapi.map.MapPoi;import com.baidu.mapapi.map.MapView;import com.baidu.mapapi.map.MyLocationOverlay;import com.baidu.mapapi.map.PopupClickListener;import com.baidu.mapapi.map.PopupOverlay;import com.baidu.platform.comapi.basestruct.GeoPoint;import com.example.baidumap.R;public class MainActivity extends Activity { //声明控件 private Button request; private Toast mToast=null; private BMapManager mBMapManager=null; private MapView mMapView = null; //MapView 是地图主控件 private MapController mMapController = null;//用MapController完毕地图控制 private LocationClient mLocClient; public LocationData mLocData = null; private LocationOverlay myLocationOverlay = null;//定位图层 private boolean isRequest = false;//是否手动触发请求定位 private boolean isFirstLoc = true;//是否首次定位 private PopupOverlay mPopupOverlay = null;//弹出泡泡图层,浏览节点时使用 private View viewCache=null; public BDLocation location = new BDLocation(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //**使用地图sdk前需先初始化BMapManager,这个必须在setContentView()先初始化 mBMapManager = new BMapManager(this); //第一个參数是API key, 第二个參数是经常使用事件监听,用来处理通常的网络错误,授权验证错误等,你也能够不加入这个回调接口 mBMapManager.init("LDtH1sVwr7kygaF0aTqaVwWU", new MKGeneralListener() { //授权错误的时候调用的回调函数 @Override public void onGetPermissionState(int iError) { if (iError == MKEvent.ERROR_PERMISSION_DENIED) { showToast("API KEY错误, 请检查!"); } } //一些网络状态的错误处理回调函数 @Override public void onGetNetworkState(int iError) { if (iError == MKEvent.ERROR_NETWORK_CONNECT) { Toast.makeText(getApplication(), "您的网络出错啦!", Toast.LENGTH_LONG).show(); } } }); //初始化 init(); //单击事件 click(); } //* 显示Toast消息 private void showToast(String msg){ if(mToast == null){ mToast = Toast.makeText(this, msg, Toast.LENGTH_SHORT); }else{ mToast.setText(msg); mToast.setDuration(Toast.LENGTH_SHORT); } mToast.show(); } private void click() { request.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { requestLocation(); } }); } @Override protected void onResume() { //MapView的生命周期与Activity同步,当activity挂起时需调用MapView.onPause() mMapView.onResume(); mBMapManager.start();//又一次启动 super.onResume(); } @Override protected void onPause() { //MapView的生命周期与Activity同步,当activity挂起时需调用MapView.onPause() mMapView.onPause(); super.onPause(); } private void init() { //使用自定义的title,注意顺序 setContentView(R.layout.activity_main); //activity的布局 //这里是加入自定义的titlebtn.xml //通过id找到他们 mMapView = (com.baidu.mapapi.map.MapView) findViewById(R.id.bmapView); mMapController=mMapView.getController(); //获取地图控制器 mMapController.enableClick(true); //设置地图是否响应点击事件 request=(Button)findViewById(R.id.request); viewCache = LayoutInflater.from(this).inflate(R.layout.pop_layout, null); mPopupOverlay= new PopupOverlay(mMapView, new PopupClickListener() {// * 点击弹出窗体图层回调的方法 @Override public void onClickedPopup(int arg0) { //隐藏弹出窗体图层 mPopupOverlay.hidePop(); } }); mMapController.enableClick(true); //* 设置地图是否响应点击事件 . mMapController.setZoom(12); // * 设置地图缩放级别 mMapView.setBuiltInZoomControls(true); // * 显示内置缩放控件 mMapView.setTraffic(true); mLocData = new LocationData(); mLocClient = new LocationClient(getApplicationContext()); // * 定位SDK的核心类 //实例化定位服务,LocationClient类必须在主线程中声明 mLocClient.registerLocationListener(new BDLocationListenerImpl());//注冊定位监听接口 /** * 设置定位參数 */ LocationClientOption option = new LocationClientOption(); option.setOpenGps(true); //打开GPRS option.setAddrType("all");//返回的定位结果包括地址信息 option.setCoorType("bd09ll");//返回的定位结果是百度经纬度,默认值gcj02 option.setScanSpan(5000); //设置发起定位请求的间隔时间为5000ms option.disableCache(false);//禁止启用缓存定位 option.setPoiNumber(5); //最多返回POI个数 option.setPoiDistance(1000); //poi查询距离 option.setPoiExtraInfo(true); //是否须要POI的电话和地址等具体信息 mLocClient.setLocOption(option); mLocClient.start(); // 调用此方法開始定位 myLocationOverlay = new LocationOverlay(mMapView);//定位图层初始化 //将定位数据设置到定位图层里 myLocationOverlay.setMarker(getResources().getDrawable(R.drawable.set)); //加入定位图层 mMapView.getOverlays().add(myLocationOverlay); myLocationOverlay.enableCompass(); //更新图层数据运行刷新后生效 mMapView.refresh(); /* //准备要加入的Overlay double mLat1 = 39.910159; double mLon1 = 119.544697; // 用给定的经纬度构造GeoPoint,单位是微度 (度 * 1E6) GeoPoint p1 = new GeoPoint((int) (mLat1 * 1E6), (int) (mLon1 * 1E6)); //准备overlay图像数据,依据实情情况修复 Drawable mark= getResources().getDrawable(R.drawable.set); //用OverlayItem准备Overlay数据 OverlayItem item1 = new OverlayItem(p1,"item1","item1"); //使用setMarker()方法设置overlay图片,假设不设置则使用构建ItemizedOverlay时的默认设置 //创建IteminizedOverlay CustomItemizedOverlay itemOverlay = new CustomItemizedOverlay(mark, mMapView); //将IteminizedOverlay加入到MapView中 mMapView.getOverlays().clear(); mMapView.getOverlays().add(itemOverlay); //如今全部准备工作已准备好,使用下面方法管理overlay. //加入overlay, 当批量加入Overlay时使用addItem(List)效率更高 itemOverlay.addItem(item1); //删除overlay . //itemOverlay.removeItem(itemOverlay.getItem(0)); //mMapView.refresh(); //清除overlay // itemOverlay.removeAll(); // mMapView.refresh(); mMapView.refresh(); */ // mMapController.setCenter(p1); mMapView.regMapViewListener(mBMapManager, new MKMapViewListener() { // * 地图移动完毕时会回调此接口 方法 @Override public void onMapMoveFinish() { showToast("地图移动完毕!"); } //* 地图加载完毕回调此接口方法 @Override public void onMapLoadFinish() { showToast("地图加载完毕!"); } //* 地图完毕带动画的操作(如: animationTo())后,此回调被触发 @Override public void onMapAnimationFinish() { } //当调用过 mMapView.getCurrentMap()后,此回调会被触发 可在此保存截图至存储设备 @Override public void onGetCurrentMap(Bitmap arg0) { } //* 点击地图上被标记的点回调此方法 @Override public void onClickMapPoi(MapPoi arg0) { if (arg0 != null){ showToast(arg0.strText); } } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); CreateMenu(menu); return true; } private void CreateMenu(Menu menu){ MenuItem mnu1 =menu.add(0,0,0,"显示卫星地图"); { mnu1.setAlphabeticShortcut('a');//设置快捷键 //mnu1.serIcon(R.drawable.icon);//设置图片 } MenuItem mnu2 =menu.add(0,1,1,"显示街道地图"); { mnu2.setAlphabeticShortcut('b');//设置快捷键 //mnu1.serIcon(R.drawable.icon);//设置图片 } MenuItem mnu3 =menu.add(0,2,2,"3D地图"); { mnu3.setAlphabeticShortcut('c');//设置快捷键 //mnu1.serIcon(R.drawable.icon);//设置图片 } } @Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId() == 0){ mMapView.setSatellite(true); //设置显示为卫星地图: mMapView.setTraffic(false); }else if(item.getItemId() == 1){ mMapView.setTraffic(true); //显示街道地图 mMapView.setSatellite(false); }else if(item.getItemId() == 2){ //mMapView.se } return true; } public class BDLocationListenerImpl implements BDLocationListener { // * 接收异步返回的定位结果,參数是BDLocation类型參数 @Override public void onReceiveLocation(BDLocation location) { if (location == null) { return; } /* StringBuffer sb = new StringBuffer(256); 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("\naddr : "); sb.append(location.getAddrStr()); } */ MainActivity.this.location = location; mLocData.latitude = location.getLatitude(); mLocData.longitude = location.getLongitude(); //假设不显示定位精度圈,将accuracy赋值为0就可以 mLocData.accuracy = location.getRadius(); mLocData.direction = location.getDerect(); //将定位数据设置到定位图层里 myLocationOverlay.setData(mLocData); //更新图层数据运行刷新后生效 mMapView.refresh(); if(isFirstLoc || isRequest){ //将给定的位置点以动画形式移动至地图中心 mMapController.animateTo(new GeoPoint( (int) (location.getLatitude() * 1e6), (int) (location.getLongitude() * 1e6))); showPopupOverlay(location); //加载时候就弹出 isRequest = false; } isFirstLoc = false; } // 接收异步返回的POI查询结果,參数是BDLocation类型參数 @Override public void onReceivePoi(BDLocation poiLocation) { } } private void requestLocation() { isRequest = true; if(mLocClient != null && mLocClient.isStarted()){ showToast("正在定位......"); mLocClient.requestLocation(); } } //继承MyLocationOverlay重写dispatchTap方法 private class LocationOverlay extends MyLocationOverlay{ public LocationOverlay(MapView arg0) { super(arg0); } // * 在“我的位置”坐标上处理点击事件。 @Override protected boolean dispatchTap() { //点击我的位置显示PopupOverlay showPopupOverlay(location); return super.dispatchTap(); } @Override public void setMarker(Drawable arg0) { super.setMarker(arg0); } } @Override protected void onDestroy() { //MapView的生命周期与Activity同步,当activity销毁时需调用MapView.destroy() mMapView.destroy(); //退出应用调用BMapManager的destroy()方法 if(mBMapManager != null){ mBMapManager.destroy(); mBMapManager = null; } //退出时销毁定位 if (mLocClient != null){ mLocClient.stop(); } super.onDestroy(); } //* 显示弹出窗体图层PopupOverlay private void showPopupOverlay(BDLocation location){ TextView popText = ((TextView)viewCache.findViewById(R.id.location_tips)); popText.setText("[我的位置]\n" + location.getAddrStr()); mPopupOverlay.showPopup(getBitmapFromView(popText), new GeoPoint((int)(location.getLatitude()*1e6), (int)(location.getLongitude()*1e6)), 15); } // * 将View转换成Bitmap的方法 public static Bitmap getBitmapFromView(View view) { view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); view.buildDrawingCache(); Bitmap bitmap = view.getDrawingCache(); return bitmap; } }
大家注意:这里我把上一次的加入marker的代码凝视了,原因是当我这两个同一时候弄的时候会无法给当前位置加入标记。。。这个问题稍后会得到解决。
以下的布局文件是弹出框的布局,一个 非常easy的文件:pop_layout.xml
/>
- LocationClient 定位SDK的核心类,LocationClient类必须在主线程中声明。须要Context类型的參数。Context须要时全进程有效的context,推荐用getApplicationConext获取全进程有效的context,我们调用registerLocationListener(BDLocationListener)方法来注冊定位监听接口,BDLocationListener里面有两个方法,onReceiveLocation()(接收异步返回的定位结果),onReceivePoi()(接收异步返回的POI查询结果,POI是“Point of Interest”的缩写,能够翻译成“信息点”,每一个POI包括四方面信息,名称、类别、经度、纬度、附近的酒店、饭店,商铺等信息。我们能够叫它为“导航地图信息”,导航地图数据是整个导航产业的基石),我们这里仅仅须要重写onReceiveLocation即可了
- BDLocation 封装了定位SDK的定位结果,在BDLocationListener的onReceive方法中获取。通过该类用户能够获取error code,位置的坐标,精度半径,地址等信息,对于其getLocType ()方法获取的error code一些情况
- 61 : GPS定位结果
- 62 : 扫描整合定位根据失败。此时定位结果无效。
- 63 : 网络异常,没有成功向server发起请求。此时定位结果无效。
- 65 : 定位缓存的结果。
- 66 : 离线定位结果。通过requestOfflineLocaiton调用时相应的返回结果
- 67 : 离线定位失败。通过requestOfflineLocaiton调用时相应的返回结果
- 68 : 网络连接失败时,查找本地离线定位时相应的返回结果
- 161: 表示网络定位结果
- 162~167: 服务端定位失败
- LocationClientOption 用来设置定位SDK的定位方式,比方设置打开GPS,设置是否须要地址信息,设置发起定位请求的间隔时间等等,參数设置完后调用LocationClient 的setLocOption方法
- LocationOverlay MyLocationOverlay的子类,重写里面的dispatchTap()方法,显示弹出窗体图层PopupOverlay,调用mMapView.getOverlays().add(myLocationOverlay)就将我的位置图层加入到地图里面
- PopupOverlay 弹出图层,这个类还是比較简单,里面仅仅有三个方法,hidePop() (隐藏弹出图层)showPopup(Bitmap pop, GeoPoint point, int yOffset) (显示弹出图层)和showPopup显示多张图片的重载方法,因为showPopup方法仅仅接受Bitmap对象,所以我们必须将我们的弹出图层View对象转换成Bitmap对象,我们调用getBitmapFromView方法就实现这一转换
- BDLocationListener接口的onReceiveLocation(BDLocation location) 方法我还要重点解说下,我们会发现onReceiveLocation方法会重复运行,他运行的间隔跟LocationClientOption类的setScanSpan()方法设定的值有关,我们设定的是5000毫秒,则onReceiveLocation方法每隔5秒运行一次,注意,当我们设定的值大于1000(ms),定位SDK内部使用定时定位模式。调用requestLocation( )后,每隔设定的时间,定位SDK就会进行一次定位。假设定位SDK根据定位根据发现位置没有发生变化,就不会发起网络请求,返回上一次定位的结果;假设发现位置改变,就进行网络请求进行定位,得到新的定位结果。假设你仅仅须要定位一次的话,这个设置小于1000,或者不用设置就能够了,定时定位时,调用一次requestLocation,会定时监听到定位结果
还有非常重要的一点就是在 AndroidManifest.xml中加入以下的内容
<service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote" > </service> <meta-data android:name="com.baidu.lbsapi.API_KEY" android:value="6KOX4mXHeBRzgriV6OP1T2Hw" /> <!-- 致命的一句 -->
当中的meta-data问题:网上这样说,大家记住就得了。。。。
由于单独的定位sdk须要一个key值,而定位sdk的值又不像mapManager中能够直接赋值
所以就须要在注冊表单中注冊
执行图示:
apk地址:
部分内容摘自百度官方文档。部分来自博客:
定位自己的位置基本就这些内容,出现的问题随后会补充上。。今天就这样吧。。吃饭去了。。