扭秧歌,已经冲出国门走向世界了。英文音译为“New Younger”!
它的步法特别有意思,就是走三歩而退一步。就好像无论走到哪都要回到原点一样。
非常巧的是,我在BaiduMapsApiDemo中也遇到了这种情况。
从Demo的主界面选择“定位图层展示---LocationOverlayDemo”(对,又是这个LocationOverlayDemo)。
这个定位功能会通过网络或离线等方法为你定位到当前位置并以一个在屏幕居中闪动的蓝点标示,当你滑动屏幕看地图的其他部分时,
松开手指后的瞬间,画面又回到刚刚的位置。无论你滑到哪里,只要你松手,那么就又会回到你的位置。这个怪现象被我称为扭秧歌步法。
定位的功能是由定位SDK提供的,其基本定位功能指的是根据用户实际需求,返回用户当前位置的基础定位服务(包含GPS和网络定位(Wi-Fi和基站定位)功能)。
定位SDK的核心类是LocationClient,主要负责定位的方方面面。
定位结束后在BDLocationListener接口内处理。
地图API中的辅助类有:
MyLocationOverlay,地图上的overlay,用以显示当前的位置(那个蓝点点就是但不限于它)。
LocationData,存储定位信息如经纬度,GPS信息等。
正常的定位初始化如下:
//定位初始化 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();能够正常定位,说明初始化成功。看看定位后的代码,MyLocationListenner类实现BDLocationListener接口:
public class MyLocationListenner implements BDLocationListener { @Override public void onReceiveLocation(BDLocation location) { 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(); //是手动触发请求或首次定位时,移动到定位点 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; } //首次定位完成 isFirstLoc = false; } public void onReceivePoi(BDLocation poiLocation) { if (poiLocation == null){ return ; } } }
上面的代码,表面上看也没有什么问题,只有在手动请求和首次加载时才会调用MapController的animateTo当前位置。但是,需要了解一下其他背景信息:
1)LocationClientOption的SetScanSpan()方法说明:
当所设的整数值大于等于1000(ms)时,定位SDK内部使用定时定位模式。调用requestLocation( )后,每隔设定的时间,定位SDK就会进行一次定位。如果定位SDK根据定位依据发现位置没有发生变化,就不会发起网络请求,返回上一次定位的结果;如果发现位置改变,就进行网络请求进行定位,得到新的定位结果。定时定位时,调用一次requestLocation,会定时监听到定位结果。
当不设此项,或者所设的整数值小于1000(ms)时,采用一次定位模式。每调用一次requestLocation( ),定位SDK会发起一次定位。请求定位与监听结果一一对应。
设定了定时定位后,可以热切换成一次定位,需要重新设置时间间隔小于1000(ms)即可。locationClient对象stop后,将不再进行定位。如果设定了定时定位模式后,多次调用requestLocation(),则是每隔一段时间进行一次定位,同时额外的定位请求也会进行定位,但频率不会超过1秒一次。
记得上面我们设置了1000吧,也就是说,会每秒钟出发定位与监听事件。
2)MapView的refresh方法:刷新地图。
综合上述两点,现象的解释如下:
每秒钟返回定位信息后,都会执行地图刷新,而如果你没移动地图是不会有问题的,但就像上面说的,滑动屏幕去看其他地图时,地图的刷新就会使你又回到当前位置的画面。
那么如何解决呢?
有两种方法可以解决扭秧歌步法的问题,看看哪种更加适合自己的需求吧。
1)把mMapView.refresh()放到if语句内。
2)将ScanSpan设置在1000以内或者不设,如option.setScanSpan(500);
从Demo代码中我们会看到Baidu地图API开发中一个侧面,给人留下一种很着急的印象。下一篇想通过几个例子来说一说Demo中的问题。