Android NDK开发详解用户位置信息之请求位置信息更新
适当地使用位置信息能够为应用的用户带来好处。例如,如果应用要在用户步行或驾车时帮助他们寻路,或者如果应用要跟踪资产的位置,那么就需要定期获取设备的位置信息。除了地理位置(纬度和经度)之外,您可能还需要向用户提供其他信息,如设备的方位(水平行进方向)、高度或速度。Location 对象中提供了这些信息以及更多信息,应用可以从一体化位置信息提供程序中检索这些信息。作为响应,API 会根据 WLAN 和 GPS(全球定位系统)等当前可用的位置信息提供程序,以可用的最佳位置信息定期更新应用。位置信息的准确度取决于提供程序、您已请求的位置权限,以及您在位置信息请求中设置的选项。
本课将介绍如何在一体化位置信息提供程序中使用 requestLocationUpdates() 方法请求对设备的位置信息进行定期更新。
获取最近一次的已知位置
设备最近一次的已知位置提供了一个方便的起点,可确保应用在开始定期更新位置信息之前具有已知位置。获取最近一次的已知位置一课将向您介绍如何通过调用 getLastLocation() 获取最近一次的已知位置。下面几部分中的代码段假定您的应用已检索到最近一次的已知位置,并将其作为 Location 对象存储在全局变量 mCurrentLocation 中。
发出位置信息请求
在请求位置信息更新之前,应用必须连接到位置信息服务并发出位置信息请求。更改位置信息设置一课将向您介绍如何执行此操作。发出位置信息请求后,即可通过调用 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,该标志用于跟踪用户已开启还是已关闭位置信息更新。如果用户已关闭位置信息更新,您可以告知他们应用要求访问位置信息。如需详细了解如何在 activity 实例间保留该布尔标志的值,请参阅保存 activity 的状态。
定义位置信息更新回调
一体化位置信息提供程序会调用 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
// ...
}
}
};
}
停止位置信息更新
您应考虑当 Activity 不再获得焦点时(如当用户切换到另一个应用或切换到同一应用中的另一个 Activity 时)是否要停止位置信息更新。这样便于减少耗电量,前提是应用即使在后台运行时也不需要收集信息。本部分介绍如何在 Activity 的 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 跟踪当前是否开启了位置信息更新。在 Activity 的 onResume() 方法中,检查位置信息更新当前是否处于活跃状态,如果未处于活跃状态,请将其激活:
Kotlin
override fun onResume() {
super.onResume()
if (requestingLocationUpdates) startLocationUpdates()
}
Java
@Override
protected void onResume() {
super.onResume();
if (requestingLocationUpdates) {
startLocationUpdates();
}
}
保存 Activity 的状态
设备配置的更改(如屏幕方向或语言的更改)可能会导致当前 Activity 被销毁。因此,应用必须存储重新创建该 Activity 所需的所有信息。为了实现此目的,一种方法是使用存储在 Bundle 对象中的实例状态。
以下代码示例展示了如何使用 Activity 的 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() 方法,以从上一个 Activity 实例中恢复保存的值(如果有)。从 Activity 的 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 中。您可以在 Activity 的 onPause() 方法中设置共享偏好设置,并在 onResume() 中检索偏好设置。如需详细了解如何保存偏好设置,请阅读保存键值集。
其他资源
要了解详情,请参考以下资源:
示例
示例应用演示了如何在 Android 中接收位置信息更新。
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2023-06-12。