在之前的教程《进阶:如何编程实现开启或关闭GPS?》中,讲述了GPS开关的问题,包括了Android 2.2以及之前版本的2种不同的开关方法。虽然我说过在官方的Dev Guide中有相当详细的Location定位的说明,不过我决定还是将这个教程补齐。
在本教程中,我会分别讲述如何开启位置服务的监听,如何停止监听,如何获得不同精度的定位,以及如何判断定位是否更精确。
Android中的定位服务的相关类基本上都在android.location包中,下面会按编写的顺序依次讲解。

位置服务管理器(LocationManager)

首先,我们需要1个LocationManager,考虑到它会被多个方法使用,我们将它定义成Activity的Field。然后在onCreate方法中为它赋值。

12345
//变量定义private LocationManager locationManager;//得到LocationManagerlocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

开启位置服务的监听

有了LocationManager之后,我们就可以开始监听位置的变化了。我们使用LocationManager中的方法:
requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)
来设置监听器。
首先,我们要注意到第1个参数,这个参数的值为2选1,分别是:LocationManager.NETWORK_PROVIDER和LocationManager.GPS_PROVIDER,前者用于移动网络中获取位置,精度较低但速度很快,后者使用GPS进行定位,精度很高但一般需要10-60秒时间才能开始第1次定位,如果是在室内则基本上无法定位。
这2种Provider本质上是互补的,在本教程中,我们会同时开启2个监听,但基于移动网络的监听只会执行一次就会被停止,而基于GPS的监听则会一直持续下去,直至用户自己停止监听。
代码片段如下:
首先,我们会声明1个监听器的内部类,这个类会同时用于2种模式的监听。还要声明1个变量,用于记录当前的位置。

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
private class MyLocationListner implements LocationListener{@Overridepublic void onLocationChanged(Location location) {// Called when a new location is found by the location provider.Log.v("GPSTEST", "Got New Location of provider:"+location.getProvider());if(currentLocation!=null){if(isBetterLocation(location, currentLocation)){Log.v("GPSTEST", "It's a better location");currentLocation=location;showLocation(location);}else{Log.v("GPSTEST", "Not very good!");}}else{Log.v("GPSTEST", "It's first location");currentLocation=location;showLocation(location);}//移除基于LocationManager.NETWORK_PROVIDER的监听器if(LocationManager.NETWORK_PROVIDER.equals(location.getProvider())){locationManager.removeUpdates(this);}}//后3个方法此处不做处理public void onStatusChanged(String provider, int status, Bundle extras) {}public void onProviderEnabled(String provider) {}public void onProviderDisabled(String provider) {}};Location currentLocation;private void showLocation(Location location){//纬度Log.v("GPSTEST","Latitude:"+location.getLatitude());//经度Log.v("GPSTEST","Longitude:+location.getLongitude());//精确度Log.v("GPSTEST","Accuracy:"+location.getAccuracy());//Location还有其它属性,请自行探索}

开始监听的代码片段:

12345678
private LocationListener gpsListener=null;private LocationListener networkListner=null;private void registerLocationListener(){networkListner=new MyLocationListner();locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 3000, 0, networkListner);gpsListener=new MyLocationListner();locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, gpsListener);}

以上的代码还是很易懂的吧,创建1个监听器对象,然后指定1个provider,然后requestLocationUpdates。在监听器中检查如果是NETWORK_PROVIDER,则取消监听,只留GPS的监听(在你的实际应用中可以根据情况来进行,因为GPS有可能会因为建筑的阻挡而暂时不工作)。

位置精度的判断

在showLocation方法中,我们打印了location的Accuracy属性,这就是精确度,一般来说NETWORK得到的位置精度一般在500-1000米,GPS得到的精度一般在5-50米,基于这个属性我们可以对精度进行判断,以决定是否采用这个精度。
你可能已经注意到上面的代码中有1个isBetterLocation方法,这是用来判断获取的位置是否更好,事实上这个方法来自于Dev Guide。我们看下这个方法的内容:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
private static final int CHECK_INTERVAL = 1000 * 30;protected boolean isBetterLocation(Location location,Location currentBestLocation) {if (currentBestLocation == null) {// A new location is always better than no locationreturn true;}// Check whether the new location fix is newer or olderlong timeDelta = location.getTime() - currentBestLocation.getTime();boolean isSignificantlyNewer = timeDelta > CHECK_INTERVAL;boolean isSignificantlyOlder = timeDelta < -CHECK_INTERVAL;boolean isNewer = timeDelta > 0;// If it's been more than two minutes since the current location,// use the new location// because the user has likely movedif (isSignificantlyNewer) {return true;// If the new location is more than two minutes older, it must// be worse} else if (isSignificantlyOlder) {return false;}// Check whether the new location fix is more or less accurateint accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());boolean isLessAccurate = accuracyDelta > 0;boolean isMoreAccurate = accuracyDelta < 0;boolean isSignificantlyLessAccurate = accuracyDelta > 200;// Check if the old and new location are from the same providerboolean isFromSameProvider = isSameProvider(location.getProvider(),currentBestLocation.getProvider());// Determine location quality using a combination of timeliness and// accuracyif (isMoreAccurate) {return true;} else if (isNewer && !isLessAccurate) {return true;} else if (isNewer && !isSignificantlyLessAccurate&& isFromSameProvider) {return true;}return false;}/** Checks whether two providers are the same */private boolean isSameProvider(String provider1, String provider2) {if (provider1 == null) {return provider2 == null;}return provider1.equals(provider2);}

从代码中可以很清楚的看出判断位置是否“更好”的准则,不仅使用了精度(getAccuracy()),还使用了时间进行判断。事实上除了在导航应用,其它的时候均可以直接使用上面的这个方法来对位置更新信息进行过滤,以减少不断更新界面而带来的性能损失。

结束监听

只需要调用LocationManager对象的removeUpdates(LocationListener listener)方法就可以停止监听。事实上,在之前的代码中你已经看到我们移除了基于移动网络的监听器,下面的代码片段用于移除GPS监听器。

1234
if(gpsListener!=null){locationManager.removeUpdates(gpsListener);gpsListener=null;}

LocationManager的其它使用

这里还要介绍LocationManager中的几个方法:
getLastKnownLocation(String provider),用于得到上次定位时的最后位置,通常在应用刚启动时立刻得到1个位置,这样应用看上去会比较快。
getBestProvider(Criteria criteria, boolean enabledOnly),根据条件(精度的高低,是否能够得到海拔等)以及当前是否开启,得到1个最好的位置Provider。看上去很美,但现在的Android系统中只有2个Provider,而大多数用户的GPS都是开启的,在仅仅是2选1的情况我想像不出这个方法的用途。而即便用户关闭了GPS,我们也有能力帮他开启,用完了之后再关掉它。开启的方法见《进阶:如何编程实现开启或关闭GPS?》。

总结

2个Provider提供了不同精度的定位服务,我们可以根据情况来使用。
一般来说,先使用NETWORK来得到1个精度较差的位置,再使用GPS来得到更准确的位置。
Android官方提供的Dev Guide中,提供了一个关于GPS使用的时间线,我们来看一下

概括起来就是2句话:“快速反应,渐进式精确”。在实际的使用中也要根据自己的情况画1个时间线,好决定何时开始监听,何时结束监听。


更多相关文章

  1. Android(安卓)用户界面---拖放(Drag and Drop)(一)
  2. Android快速自定义控件+实战演示(三)完整键盘和组合回调!
  3. 应用开发笔记 2011年10月28日 Android(安卓)使用动画效果后的控
  4. Android(安卓)手势操作GestureDetector
  5. Android监听事件的回调机制
  6. Android(安卓)UI设计之自定义Dialog,实现各种风格效果的对话框
  7. android 验证码输入框
  8. Android(安卓)监听系统媒体音量变化
  9. Android坐标系统常用方法属性总结

随机推荐

  1. MySQL常用存储引擎功能与用法详解
  2. MySQL用户权限验证与管理方法详解
  3. Windows下mysql5.7.10安装配置方法图文教
  4. DB为何大量出现select @@session.tx_read
  5. MySQL5.7.20解压版安装和修改root密码的
  6. CentOS7.4 源码安装MySQL8.0的教程详解
  7. centos7上mysql8.0rpm方式安装教程图解
  8. Linux下如何实现Mysql定时任务
  9. 详解Mysql中日期比较大小的方法
  10. mysql数据库如何实现亿级数据快速清理