2012年9月24日星期一

Android开发笔记(六)

  • Android开发笔记(六)

     -- GPS定位开发总结



  • 接口说明
简单介绍Android SDK 提供的GPS定位接口,主要包含三要点,如下
* Android系统定位服务管理类LocationManager
android.location.LocationManager
You do not instantiate this class directly; instead, retrieve it through Context.getSystemService(Context.LOCATION_SERVICE).

* 请求更新定位信息requestLocationUpdates
void android.location.LocationManager.requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)

public void requestLocationUpdates (String provider, long minTime, float minDistance, LocationListener listener)

* 获取系统缓存最新的定位信息

Location android.location.LocationManager.getLastKnownLocation(String provider)

public Location getLastKnownLocation (String provider)


  • 示例说明
* 开启位置服务的监听

     private class MyLocationListner implements LocationListener {
          @Override
          public void onStatusChanged(String provider, int status, Bundle extras) {
          }
          @Override
          public void onProviderEnabled(String provider) {
          }
          @Override
          public void onProviderDisabled(String provider) {
          }
          @Override
          public void onLocationChanged(Location location) {
               // Called when a new location is found by the location provider.
               if(currentLocation!=null){
                    if(isBetterLocation(location, currentLocation)){
                         currentLocation=location;
                         showLocation(location);
               } else {
                    currentLocation=location;
                    showLocation(location);
               }
               //移除基于LocationManager.NETWORK_PROVIDER的监听器
               if(LocationManager.NETWORK_PROVIDER.equals(location.getProvider())){
                    locationManager.removeUpdates(this);
               }    
          }
     };
    
    
     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);
     }

* 位置精度的判断

     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 location
                    return true;
          }

          // Check whether the new location fix is newer or older
          long 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 moved
          if (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 accurate
          int 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 provider
          boolean isFromSameProvider = isSameProvider(location.getProvider(),
                              currentBestLocation.getProvider());

          // Determine location quality using a combination of timeliness and
          // accuracy
          if (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);
     }
    
* 结束监听

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



  •  问题与总结
1. 系统开启GPS服务,都是比较耗电的;
2. (由于耗电)绝大部分用户默认不开启GPS服务;
3. 首次获取GPS定位信息,可能需要比较长的时间;
4. 经诸多实验结果得出结论在室内几乎无法获取GPS定位信息。

PS. 缺点2,3都是比较致命的。按理说,GPS服务是借助卫星通信定位的,在没有网络连接情况下也能用。

以上示例代码在室内几乎无法GPS定位(NETWORK或基站定位没问题),所以建议再真正的实际项目里,至少使用NETWORK和GPS两种不同的Location Provider实现定位功能。两种Provider提供了不同精度的定位服务,我们可以根据情况来使用。一般来说,先使用NETWORK来得到1个精度较差的位置,再使用GPS来得到更准确的位置。
参照Android官方提供的Dev Guide中,提供的一个关于GPS使用的时间线。如下:
“概括起来就是2句话:“快速反应,渐进式精确”。在实际的使用中也要根据自己的情况画1个时间线,好决定何时开始监听,何时结束监听。”


1. 注册两个LocationListener,同时监听GPS_PROVIDER和NETWORK_PROVIDER的定位结果;
2. 可以调用getLastKnownLocation获得一个Location值,作为最初的备选值;
3. 在用户可接受的时间内,接收从onLocationChanged返回的位置信息,并同旧值做比较选取最佳结果,需选取算法;
4. 判断筛选后的最佳结果,是否可接受。若可接受则返回给用户,否则告之无法定位等提示。



  •  参考资料


没有评论:

发表评论