接着昨天的百度地图话题,今天要写一下我的一个拙劣的糅合基础服务,定位服务和绘制服务的程序。怎么建立基本地图应用前面已经说了,现在开始做这个东东,来达到认识百度地图各种特性的目的。
程序基本上是建立在百度的demo上面,基本做法是照搬demo里面的MyLocationDemoActivity。然后加入绘制的代码即可。
照搬demo的代码
首先,我们得实现appication来监听是否连接网络和是否认证好我们的key
public class MyApplication extends Application{
private static MyApplication mInstance = null;
public boolean m_bKeyRight = true;
BMapManager mBMapManager = null;
@Override
public void onCreate() {
super.onCreate();
mInstance = this;
initEngineManager(this);
// Toast.makeText(MyApplication.getInstance().getApplicationContext(),
// "开始!", Toast.LENGTH_LONG).show();
}
public void initEngineManager(Context context) {
if (mBMapManager == null) {
mBMapManager = new BMapManager(context);
}
if (!mBMapManager.init(new MyGeneralListener())) {
Toast.makeText(MyApplication.getInstance().getApplicationContext(),
"BMapManager 初始化错误!", Toast.LENGTH_LONG).show();
}
}
public static MyApplication getInstance() {
return mInstance;
}
// 常用事件监听,用来处理通常的网络错误,授权验证错误等
static class MyGeneralListener implements MKGeneralListener {
@Override
public void onGetNetworkState(int iError) {
if (iError == MKEvent.ERROR_NETWORK_CONNECT) {
Toast.makeText(MyApplication.getInstance().getApplicationContext(), "您的网络出错啦!",
Toast.LENGTH_LONG).show();
}
else if (iError == MKEvent.ERROR_NETWORK_DATA) {
Toast.makeText(MyApplication.getInstance().getApplicationContext(), "输入正确的检索条件!",
Toast.LENGTH_LONG).show();
}
// ...
}
@Override
public void onGetPermissionState(int iError) {
//非零值表示key验证未通过
if (iError != 0) {
//授权Key错误:请在 DemoApplication.java文件输入正确的授权Key,并
Toast.makeText(MyApplication.getInstance().getApplicationContext(),
"检查您的网络连接是否正常!error: "+iError, Toast.LENGTH_LONG).show();
MyApplication.getInstance().m_bKeyRight = false;
}
else{
MyApplication.getInstance().m_bKeyRight = true;
Toast.makeText(MyApplication.getInstance().getApplicationContext(),
"key认证成功", Toast.LENGTH_LONG).show();
}
}
}
}
然后就是activity里面,activity照抄MyLocationDemoActivity,有几个地方需要注意。
在onCreate里面初始化BMapManager类和appication:
MyApplication app = (MyApplication) this.getApplication();
if (app.mBMapManager == null) {
app.mBMapManager = new BMapManager(getApplicationContext());
/**
* 如果BMapManager没有初始化则初始化BMapManager
*/
app.mBMapManager.init(new MyApplication.MyGeneralListener());
}
地图初始化
// 地图初始化
mMapView = (MyLocationMapView) findViewById(R.id.bmapView);
mMapController = mMapView.getController();
mMapController.enableClick(true);
mMapView.getController().setZoom(14);
mMapView.getController().enableClick(true);
mMapView.setBuiltInZoomControls(true);
定位相关的
// 定位初始化
mLocClient = new LocationClient(this);
locData = new LocationData();
mLocClient.registerLocationListener(myListener);
LocationClientOption option = new LocationClientOption();
option.setOpenGps(true);// 打开gps
option.setCoorType("bd09ll"); // 设置坐标类型
option.setScanSpan(1000);
mLocClient.setLocOption(option);
mLocClient.start();
// 定位图层初始化
myLocationOverlay = new locationOverlay(mMapView);
// 设置定位数据
myLocationOverlay.setData(locData);
// 添加定位图层
mMapView.getOverlays().add(myLocationOverlay);
myLocationOverlay.enableCompass();
// 修改定位数据后刷新图层生效
// mMapView.refresh();
定位监听:(这个改动比较大,是为了我的程序写的一些逻辑)
/**
* 定位SDK监听函数
*/
public class MyLocationListenner implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
double distance;
if (location == null)
return;
locData.latitude = location.getLatitude();
locData.longitude = location.getLongitude();
// 如果不显示定位精度圈,将accuracy赋值为0即可
locData.accuracy = location.getRadius();
// 此处可以设置 locData的方向信息, 如果定位 SDK 未返回方向信息,用户可以自己实现罗盘功能添加方向信息。
locData.direction = location.getDerect();
// 更新定位数据
myLocationOverlay.setData(locData);
// 更新图层数据执行刷新后生效
// mMapView.refresh();
mHandler.sendEmptyMessage(REFRESH_MAP);
// 是手动触发请求或首次定位时,移动到定位点
Log.e("busy", "busy9");
if (isRequest || isFirstLoc) {
// 移动地图到定位点
Log.d("LocationOverlay", "receive location, animate to it");
mMapController.animateTo(new GeoPoint((int) (locData.latitude * 1e6),
(int) (locData.longitude * 1e6)));
isRequest = false;
// myLocationOverlay.setLocationMode(LocationMode.FOLLOWING);
// requestLocButton.setText("跟随");
// mCurBtnType = E_BUTTON_TYPE.FOLLOW;
if (isFirstLoc) {
p1LL.setLatitudeE6((int) (locData.latitude * 1e6));
p1LL.setLongitudeE6((int) (locData.longitude * 1e6));
preNetType = check234G();
currentNetType = preNetType;
sendAddPointMsg(p1LL);
// sendWriteResultMsg(p1LL);
mHandler.sendEmptyMessage(PRINT_OLD_POINT);
} else {
p2LL.setLatitudeE6((int) (locData.latitude * 1e6));
p2LL.setLongitudeE6((int) (locData.longitude * 1e6));
distance = getDistance();
if (distance > markDistance) {
// if(distance < maxDistance ||
// !isAutoRecord){//去除误差较大的点
// 添加标记点,并写入结果
sendAddPointMsg(p2LL);
// sendWriteResultMsg(p2LL);
p1LL.setLatitudeE6((int) (locData.latitude * 1e6));
p1LL.setLongitudeE6((int) (locData.longitude * 1e6));
Log.e(TAG, "Mark!");
// }else{
// Toast.makeText(mContext,
// getResString(R.string.distance_is_too_long) + "\n" +
// distance,
// Toast.LENGTH_LONG).show();
// }
} else {
Toast.makeText(mContext,
getResString(R.string.distance_is_too_short) + "\n" + distance,
Toast.LENGTH_LONG).show();
}
}
}
// 首次定位完成
isFirstLoc = false;
}
添加自绘图层
以上这些在demo里面都是现成的,只是介绍下各个模块的作用。然后,下面就介绍一下,怎么添加自己绘制的图层首先,添加图层需要 定义图层
private MyOverlay mOverlay = null;
private ArrayList<OverlayItem> mItems = null;
初始化图层并添加到地图上
mOverlay = new MyOverlay(getResources().getDrawable(R.drawable.icon_gcoding), mMapView);
mMapView.getOverlays().add(mOverlay);
MyOverlay是继承ItemizedOverlay的,为了响应图层点击事件,我们需要在这个自定义类里面实现相关操作
public class MyOverlay extends ItemizedOverlay {
public MyOverlay(Drawable defaultMarker, MapView mapView) {
super(defaultMarker, mapView);
}
// 响应点击
@Override
public boolean onTap(int index) {
OverlayItem item = getItem(index);
button.setText(item.getTitle());
GeoPoint pt = new GeoPoint((int) (item.getPoint().getLatitudeE6()),
(int) (item.getPoint().getLongitudeE6()));
// 弹出自定义View
pop.showPopup(button, pt, 32);
return true;
}
@Override
public boolean onTap(GeoPoint pt, MapView mMapView) {
if (pop != null) {
pop.hidePop();
mMapView.removeView(button);
}
return false;
}
}
以下是添加绘制点的方法,也是绘制的关键。在需要绘制点的地方,调用这个方法即可。参数是经度(mLat),纬度(mLon),和写入点的内容(network)。
/**
* 添加标记点
*/
public void addPoint(int mLat, int mLon, String network) {
GeoPoint p = new GeoPoint(mLat, mLon);
OverlayItem item = new OverlayItem(p, network, "");
item.setMarker(getResources().getDrawable(R.drawable.icon_gcoding));
/**
* 将item 添加到overlay中 注意: 同一个itme只能add一次
*/
mOverlay.addItem(item);
/**
* 保存所有item,以便overlay在reset后重新添加
*/
mItems.addAll(mOverlay.getAllItem());
// mMapView.refresh();
mHandler.sendEmptyMessage(REFRESH_MAP);
}
manifest相关
值得注意的是,manifest里面还有些东西需要配置,其实文档也说得清清楚楚的在appication外面添加
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="false"
android:resizeable="true"
android:smallScreens="true" />
在appication里面添加
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" >
这个服务异常重要,不添加你就无法使用百度的定位服务了。我在这里绕了许久
另外当然还有你的key,上一篇有介绍,这里不说了。
还有添加一些权限,复制demo里面所有权限过来就好了
总结
我也知道我说得很乱没有章法,不过水平就是这样的啦。那总结好好说说。首先,我要说的一点是,百度地图的坐标不是真实坐标,是经过一定的偏移的。但是,百度给出的地图也是经过偏移的,所以负负得正,总的来说你看到的百度地图位置还是很准的。这个问题得益于我们的国家政策,强制偏移电子地图。对于这个问题,可以试试下面的代码得到的坐标,这个是真实的坐标,可以看看在百度地图上定位到了哪里。
LocationClient mLocationClient = = new LocationClient(getApplicationContext(), this, // ConnectionCallbacks
this);
lat = mLocationClient.getLastLocation().getLatitude();
lon = mLocationClient.getLastLocation().getLongitude();
百度地图使用GPS,基站,网络混合定位,定位准确度还是比较高的,而且百度对比谷歌地图的优势在于,百度地图提供了更加丰富的路径规划和兴趣点的服务。而且全中文的文档也是非常易懂。
下面再提供一个可能会常用到的,计算两点之间距离的方法:
public double getDistance(GeoPoint p1LL, GeoPoint p2LL) {
double dis;
try {
dis = DistanceUtil.getDistance(p1LL, p2LL);
} catch (Exception e) {
e.printStackTrace();
dis = -1;
}
Log.e(TAG, "Distance is: " + dis);
return dis;
}