LocationManager
中有很多方法,使得应用可以获取位置更新。
典型的观察者模式:注册一个事件监听器,说明location manager想从哪里接收位置更新,并且设定接收位置更新的最小时间间隔和距离间隔, onLocationChanged()
回调方法就会在时间和位置间隔相应的频率下被激发。
LocationListener是一个接口,用于接收LocationManager关于位置变化的通知。
需要通过requestLocationUpdates(String, long, float, LocationListener)进行监听器的注册。
LocationListener其中的onLocationChanged(Location location)方法每当位置变化就会被调用。
比如下面的代码例子,每隔至少10秒,或者距离变化大于10米时接收一次位置信息。
private final LocationListener listener = new LocationListener() { @Override public void onLocationChanged(Location location) { // A new location update is received. Do something useful with it. In this case, // we're sending the update to a handler which then updates the UI with the new // location. Message.obtain(mHandler, UPDATE_LATLNG, location.getLatitude() + ", " + location.getLongitude()).sendToTarget(); ... } ... }; mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, // 10-second interval. 10, // 10 meters. listener);
一般来说,更高精确度的定位方法(如GPS定位)比低精确度的定位方法(如基于网络的定位)花费更多的定位时间。
如果你想要尽快展示位置数据并且在有更好精度的信息可用的时候更新它,一个通常的做法是注册一个位置监听器,同时监听GPS和网络位置提供者。
在 onLocationChanged()
回调函数中,你可以接收多个location provider的位置更新,它们可能有不同时间间隔和不同的精度,这时候需要结合逻辑判断,舍弃过时的还有不准确的更新。
一个实现的例子:
private static final int TWO_MINUTES = 1000 * 60 * 2; /** Determines whether one Location reading is better than the current Location fix * @param location The new Location that you want to evaluate * @param currentBestLocation The current Location fix, to which you want to compare the new one */ 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 > TWO_MINUTES; boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES; 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); }
可以看到在这个实现中,判断位置信息是否是一个更好的结果,首先判断获取的位置的时间信息,是不是更新;然后检查精度、是否是同一个provider提供等信息。
一些特定应用下,获取位置的首次建立时间如果过长可能难以使用户接受。可以考虑调用 getLastKnownLocation()
方法,这个方法返回上一次的定位结果。
当然这个结果很有可能是过期的,因为中间设备可能被关闭然后移动到了一个其他的地方。可以检查返回位置的时间戳和精度,然后决定这个位置是否有用。
如果丢弃了getLastKnownLocation()
方法返回的位置,等待新的位置更新时,最好考虑显示一个合适的信息给用户。
当你不再需要位置数据时,可以关闭位置更新,以减少多余的能量消耗和网络带宽。
比如,当用户已经离开了位置更新显示的界面,就可以通过在onStop()中调用 removeUpdates()
方法来停止位置更新。如下:
protected void onStop() { super.onStop(); mLocationManager.removeUpdates(listener); }
当然也有一些应用需要持续地更新和处理位置数据,这时候最好将位置更新逻辑放在后台service中,用系统的notification bar让用户看到位置数据。
Training: Obtaining the Current Location
http://developer.android.com/training/basics/location/currentlocation.html
LocationManager类:
http://developer.android.com/reference/android/location/LocationManager.html
LocationListener接口:
http://developer.android.com/reference/android/location/LocationListener.html
Location类:
http://developer.android.com/reference/android/location/Location.html