http://www.linuxidc.com/Linux/2011-07/38867p2.htm
本篇文章主要讲解Baidu Map API中MyLocationOverlay的使用。故名思义,MyLocation中文释义为“我的位置”,而Overlay则是“图层”或“覆盖物”的意思,MyLocationOverlay的作用正是用于在地图上标注自己所处的位置。它跟使用ItemizedOverlay非常相似,只不过MyLocationOverlay标记的只有一个点。
在地图上标记用户当前所处位置其实是一个GPS定位应用。首先通过GPS定位获取到用户当前所在位置的经纬度,再将该经纬度所代表的点在地图上标出来。其实除了在地图上标注自己所处的位置外,我们通常还有这样的需求:“如果我的位置发生改变,要能够实时在地图上体现出来”。
下面我们就来一步步实现上面想要的功能,主要是通过MyLocationOverlay结合LocationListener来实现的。
1)创建布局文件res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android" Android:orientation="vertical" Android:layout_width="fill_parent" Android:layout_height="fill_parent" > <com.baidu.mapapi.MapView Android:id="@+id/map_View" Android:layout_width="fill_parent" Android:layout_height="fill_parent" Android:clickable="true" /> </LinearLayout>
2)创建Activity继承com.baidu.mapapi.MapActivity
package com.liufeng.baidumap; import Android.location.Location; import Android.os.Bundle; import com.baidu.mapapi.BMapManager; import com.baidu.mapapi.GeoPoint; import com.baidu.mapapi.LocationListener; import com.baidu.mapapi.MKLocationManager; import com.baidu.mapapi.MapActivity; import com.baidu.mapapi.MapController; import com.baidu.mapapi.MapView; import com.baidu.mapapi.MyLocationOverlay; /** * 创建Activity(继承com.baidu.mapapi.MapActivity) * * @author liufeng * @date 2011-05-02 */ public class MyLocationActivity extends MapActivity implements LocationListener { private BMapManager mapManager; private MKLocationManager mLocationManager = null; private MyLocationOverlay myLocationOverlay; private MapView mapView; private MapController mapController; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 初始化MapActivity mapManager = new BMapManager(getApplication()); // init方法的第一个参数需填入申请的API Key mapManager.init("285B415EBAB2A92293E85502150ADA7F03C777C4", null); super.initMapActivity(mapManager); mLocationManager = mapManager.getLocationManager(); // 注册位置更新事件 mLocationManager.requestLocationUpdates(this); // 使用GPS定位 mLocationManager.enableProvider((int) MKLocationManager.MK_GPS_PROVIDER); mapView = (MapView) findViewById(R.id.map_View); // 设置地图模式为交通地图 mapView.setTraffic(true); // 设置启用内置的缩放控件 mapView.setBuiltInZoomControls(true); // 构造一个经纬度点 GeoPoint point = new GeoPoint((int) (26.597239 * 1E6), (int) (106.720397 * 1E6)); // 取得地图控制器对象,用于控制MapView mapController = mapView.getController(); // 设置地图的中心 mapController.setCenter(point); // 设置地图默认的缩放级别 mapController.setZoom(7); // 添加定位图层 myLocationOverlay = new MyLocationOverlay(this, mapView); // 注册GPS位置更新的事件,让地图能实时显示当前位置 myLocationOverlay.enableMyLocation(); // 开启磁场感应传感器 myLocationOverlay.enableCompass(); mapView.getOverlays().add(myLocationOverlay); } @Override protected boolean isRouteDisplayed() { return false; } @Override protected void onDestroy() { if (mapManager != null) { mapManager.destroy(); mapManager = null; } mLocationManager = null; super.onDestroy(); } @Override protected void onPause() { if (mapManager != null) { mapManager.stop(); } super.onPause(); } @Override protected void onResume() { if (mapManager != null) { mapManager.start(); } super.onResume(); } /** * 根据MyLocationOverlay配置的属性确定是否在地图上显示当前位置 */ @Override protected boolean isLocationDisplayed() { return myLocationOverlay.isMyLocationEnabled(); } /** * 当位置发生变化时触发此方法 * * @param location 当前位置 */ @Override public void onLocationChanged(Location location) { if (location != null) { // 将当前位置转换成地理坐标点 final GeoPoint pt = new GeoPoint((int) (location.getLatitude() * 1000000), (int) (location.getLongitude() * 1000000)); // 将当前位置设置为地图的中心 mapController.setCenter(pt); } } }
简单解释:代码中是通过MyLocationOverlay在地图上标记当前所在位置的,通过实现监听器接口com.baidu.mapapi.LocationListener并重写它的onLocationChanged方法来监听位置的变化。(注意LocationListener是baidu map api里的,而不是Android自带的)
3)在AndroidManifest.xml中配置
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:Android="http://schemas.android.com/apk/res/android" package="com.liufeng.baidumap" Android:versionCode="1" Android:versionName="1.0"> <application Android:icon="@drawable/icon" android:label="@string/app_name"> <activity Android:name=".MyLocationActivity" android:label="@string/app_name"> <intent-filter> <action Android:name="android.intent.action.MAIN" /> <category Android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk Android:minSdkVersion="4" /> <!-- 访问网络的权限 --> <uses-permission Android:name="android.permission.INTERNET" /> <!-- 访问精确位置的权限 --> <uses-permission Android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 访问网络状态的权限 --> <uses-permission Android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 访问WIFI网络状态的权限 --> <uses-permission Android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- 改变WIFI网络状态的权限 --> <uses-permission Android:name="android.permission.CHANGE_WIFI_STATE" /> <!-- 读写存储卡的权限 --> <uses-permission Android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 读取电话状态的权限 --> <uses-permission Android:name="android.permission.READ_PHONE_STATE" /> </manifest>
到这里,我们的代码编写工作就已经完成了。接下来,再模拟器里运行一下,看看效果,下图是在模拟器里运行的截图:
怎么回事?不是说能够在地图上标注出当前位置的,好像并没有标注。没错,的确是没有标注出当前位置。这是什么原因呢?前面说了,我们要实现的是一个GPS结合Map的简单定位应用。手机的GPS定位是依赖于手机设备上的一块GPS物理芯片来实现的,并不是手机上装个GPS软件就能实现定位的。问题就很明显了,因为我们是在模拟器里运行上面的程序,模拟器上可没有GPS物理芯片,当然也就不能实现定位了。
好在DDMS为我们提供了模拟GPS信号的功能,它可以通过三种方式来模拟:自定义经纬度、使用GPX文件或KML文件(这些文件是GPS信息记录的文件格式)。依次点击Eclipse上的"Window"-"Show View"-"Other"-"Android"-"Emulator Control",就能够看到如下所示的界面:
这个就是用来模拟GPS信号的。可以看到有三个标签项:Manual、GPX和KML,分别对应于上面所说的“自定义经纬度”、“使用GPX文件”和“使用KML文件”三种方式来模拟GPS信号。这里我们采用第一种方式,因为它最简单,也最直观,好理解。
我们输入一个经纬度值(经度:106.720397,纬度:26.597239),然后点击“Send”按钮,模拟器将会收到该信号,这意味模拟器设备当前所处的位置正是我们所发送的这个经纬度所代表的位置,这样就能在地图上标记出当前所处位置了。真的是这样吗?那我们赶紧尝试一下。输入经纬度值的截图如下:
点击发送按钮后,再来看下模拟器上显示的地图是否发生变化:
可以看到,已经在地图上标记出了“当前位置”,就是那个蓝色的圆点。到这里我们工作还没有完,请继续往下看。
最开始的需求里有这样一条:“如果我的位置发生改变,要能够实时在地图上体现出来”,我们的代码里是否已实现该功能呢,当然。那如何来模拟演示该功能呢?其实也很简单,我们再向模拟器发送另外一组不同的经纬度值,这就相当于设备所处的位置发生了改变。比如我们再次发送的经纬度值为“经度:106.720397,纬度:24.597239”,再来看下运行结果的变化:
可以看到,当位置发生变动时,是能够时时体现在地图上的。到这里我们的所有工作就算完成了。
备注:建议如果有条件的朋友,尽量买部Android真机来做开发测试,因为模拟器并不能真实地模拟手机上的所有功能。有很多时候很可能你的程序一点问题也没有,但是由于模拟器不支持或者你不清楚如何通过模拟器来模拟某种功能而导致你反复的调试修改代码,造成不必要的时间浪费。