请求位置信息更新

适当使用位置信息可让您的应用用户受益。例如,如果您的应用可帮助用户在步行或驾驶时找到路,或者如果您的应用跟踪资产的位置,则需要定期获取设备的位置信息。除了地理位置(经纬度)之外,您可能还需要向用户提供更多信息,例如设备的方位角(水平方向)、海拔或速度。这些信息及更多信息都可在 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 中接收位置信息更新。