对位置信息的适当使用可以使您的应用用户受益。例如,如果您的应用帮助用户在步行或驾驶时找到路线,或者如果您的应用跟踪资产的位置,则它需要定期获取设备的位置。除了地理位置(纬度和经度)之外,您可能还想向用户提供更多信息,例如设备的方位(水平移动方向)、海拔或速度。此信息以及更多信息都可以在您的应用可以从 融合位置提供程序 中检索到的 Location
对象中找到。作为响应,API 会根据当前可用的位置提供程序(如 WiFi 和 GPS(全球定位系统))定期更新您的应用,提供最佳可用位置。位置的准确性由提供程序、您已请求的位置权限 以及您在位置请求中设置的选项决定。
本课程将向您展示如何使用融合位置提供程序中的 requestLocationUpdates()
方法请求有关设备位置的定期更新。
获取最后已知位置
设备的最后已知位置提供了一个方便的起点,确保应用在开始定期位置更新之前拥有已知位置。有关 获取最后已知位置 的课程将向您展示如何通过调用 getLastLocation()
来获取最后已知位置。以下部分中的代码片段假定您的应用已经检索到最后已知位置,并将其存储为全局变量 mCurrentLocation
中的 Location
对象。
发出位置请求
在请求位置更新之前,您的应用必须连接到位置服务并发出位置请求。有关 更改位置设置 的课程将向您展示如何执行此操作。一旦位置请求到位,您就可以通过调用 requestLocationUpdates()
来开始定期更新。
根据请求的形式,融合位置提供程序要么调用 LocationCallback.onLocationResult()
回调方法并将 Location
对象列表传递给它,要么发出一个包含其扩展数据中位置的 PendingIntent
。更新的准确性和频率会受到您已请求的位置权限以及您在位置请求对象中设置的选项的影响。
本课程将向您展示如何使用 LocationCallback
回调方法获取更新。调用 requestLocationUpdates()
,将您的 LocationRequest
对象实例和 LocationCallback
传递给它。如以下代码示例所示,定义一个 startLocationUpdates()
方法
Kotlin
override fun onResume() { super.onResume() if (requestingLocationUpdates) startLocationUpdates() } private fun startLocationUpdates() { fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()) }
Java
@Override protected void onResume() { super.onResume(); if (requestingLocationUpdates) { startLocationUpdates(); } } private void startLocationUpdates() { fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()); }
请注意,上面的代码片段引用了一个布尔标志 requestingLocationUpdates
,用于跟踪用户是否已打开或关闭位置更新。如果用户已关闭位置更新,您可以通知他们您的应用的位置要求。有关跨活动实例保留布尔标志值的更多信息,请参阅 保存活动的狀態。
定义位置更新回调
融合位置提供程序会调用 LocationCallback.onLocationResult()
回调方法。传入的参数包含一个包含位置纬度和经度的 Location
对象列表。以下代码片段展示了如何实现 LocationCallback
接口并定义方法,然后获取位置更新的时间戳,并在您的应用用户界面上显示纬度、经度和时间戳
Kotlin
private lateinit var locationCallback: LocationCallback // ... override fun onCreate(savedInstanceState: Bundle?) { // ... locationCallback = object : LocationCallback() { override fun onLocationResult(locationResult: LocationResult?) { locationResult ?: return for (location in locationResult.locations){ // Update UI with location data // ... } } } }
Java
private LocationCallback locationCallback; // ... @Override protected void onCreate(Bundle savedInstanceState) { // ... locationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { if (locationResult == null) { return; } for (Location location : locationResult.getLocations()) { // Update UI with location data // ... } } }; }
停止位置更新
考虑是否在活动不再处于焦点时停止位置更新,例如用户切换到另一个应用程序或切换到同一应用程序中的其他活动时。这有助于减少功耗,前提是应用程序即使在后台运行时也不需要收集信息。本节说明如何在活动的 onPause()
方法中停止更新。
要停止位置更新,请调用 removeLocationUpdates()
,并将 LocationCallback
传递给它,如以下代码示例所示
Kotlin
override fun onPause() { super.onPause() stopLocationUpdates() } private fun stopLocationUpdates() { fusedLocationClient.removeLocationUpdates(locationCallback) }
Java
@Override protected void onPause() { super.onPause(); stopLocationUpdates(); } private void stopLocationUpdates() { fusedLocationClient.removeLocationUpdates(locationCallback); }
使用布尔值 requestingLocationUpdates
来跟踪位置更新当前是否已启用。在活动的 onResume()
方法中,检查位置更新当前是否处于活动状态,如果未激活则激活它们
Kotlin
override fun onResume() { super.onResume() if (requestingLocationUpdates) startLocationUpdates() }
Java
@Override protected void onResume() { super.onResume(); if (requestingLocationUpdates) { startLocationUpdates(); } }
保存活动的状态
设备配置的更改,例如屏幕方向或语言的更改,会导致当前活动被销毁。因此,您的应用程序必须存储重新创建活动所需的所有信息。一种方法是通过存储在 Bundle
对象中的实例状态。
以下代码示例演示了如何使用活动的 onSaveInstanceState()
回调来保存实例状态
Kotlin
override fun onSaveInstanceState(outState: Bundle?) { outState?.putBoolean(REQUESTING_LOCATION_UPDATES_KEY, requestingLocationUpdates) super.onSaveInstanceState(outState) }
Java
@Override protected void onSaveInstanceState(Bundle outState) { outState.putBoolean(REQUESTING_LOCATION_UPDATES_KEY, requestingLocationUpdates); // ... super.onSaveInstanceState(outState); }
定义一个 updateValuesFromBundle()
方法来从活动的先前实例中恢复保存的值(如果可用)。从活动的 onCreate()
方法调用该方法,如以下代码示例所示
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { // ... updateValuesFromBundle(savedInstanceState) } private fun updateValuesFromBundle(savedInstanceState: Bundle?) { savedInstanceState ?: return // Update the value of requestingLocationUpdates from the Bundle. if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) { requestingLocationUpdates = savedInstanceState.getBoolean( REQUESTING_LOCATION_UPDATES_KEY) } // ... // Update UI to match restored state updateUI() }
Java
@Override public void onCreate(Bundle savedInstanceState) { // ... updateValuesFromBundle(savedInstanceState); } private void updateValuesFromBundle(Bundle savedInstanceState) { if (savedInstanceState == null) { return; } // Update the value of requestingLocationUpdates from the Bundle. if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) { requestingLocationUpdates = savedInstanceState.getBoolean( REQUESTING_LOCATION_UPDATES_KEY); } // ... // Update UI to match restored state updateUI(); }
有关保存实例状态的更多信息,请参阅 Android Activity 类参考。
注意: 为了更持久地存储,您可以在应用程序的 SharedPreferences
中存储用户的首选项。在活动的 onPause()
方法中设置共享首选项,并在 onResume()
方法中检索首选项。有关保存首选项的更多信息,请阅读 保存键值对。
其他资源
要了解更多信息,请利用以下资源
示例
- 示例应用程序 演示了在 Android 中接收位置更新。