更改位置信息设置

如果您的应用需要请求位置或接收权限更新,则设备需要启用适当的系统设置,例如 GPS 或 WLAN 扫描。您的应用不应直接启用服务(例如设备的 GPS),而应指定所需的精确度/功耗水平以及更新间隔,然后设备会自动对系统设置进行相应的调整。这些设置通过 LocationRequest 数据对象定义。

本课介绍如何使用 Settings Client 来检查启用了哪些设置,以及如何向用户提供“位置信息设置”对话框,以便用户只需点按一下就可以更新自己的设置。

配置位置信息服务

为了使用 Google Play 服务和一体化位置信息提供程序提供的位置信息服务,请使用 Settings Client 连接您的应用,然后检查当前的位置信息设置,并视需要提示用户启用所需的设置。

使用位置信息服务的应用必须请求位置权限。在本课程中,粗略的位置检测就足够了。可使用应用清单中的 uses-permission 元素请求此权限,如下例所示:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.google.android.gms.location.sample.locationupdates" >

      <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    </manifest>
    

如果设备搭载 Android 6.0 或更高版本,并且应用的目标 SDK 为 23 或更高级别,则应用必须在其清单中列出这些权限并在运行时请求这些权限。要了解详情,请参阅在运行时请求权限

如果您的应用以 Android 10(API 级别 29)或更高版本为目标平台,并且应用在后台运行时需要访问设备位置,那么您还必须声明 ACCESS_BACKGROUND_LOCATION 权限。要了解详情,请参阅有关如何请求在后台访问位置信息的章节。

设置位置请求

要保存向一体化位置信息提供程序发送的请求的参数,请创建 LocationRequest。这些参数将决定位置请求的精确度。要详细了解所有可用的位置请求选项,请参阅 LocationRequest 类参考。本课将介绍如何设置更新间隔、最快更新间隔和优先级,具体如下所述:

更新间隔
setInterval() - 该方法设置应用接收位置更新的频率(以毫秒为单位)。请注意,为了优化电池电量的使用,位置可能会以比这更高或更低的频率更新,或者可能完全不更新(例如,当设备没有网络连接时)。
最快更新间隔
setFastestInterval() - 该方法设置应用处理位置更新的最快频率(以毫秒为单位)。除非以快于 setInterval() 中指定的频率接收更新对您的应用有益,否则您无需调用此方法。
优先级

setPriority() - 此方法设置请求的优先级,这可为 Google Play 服务提供的位置信息服务提供有关使用哪些位置源的明确提示。支持使用以下值:

  • PRIORITY_BALANCED_POWER_ACCURACY - 使用此设置可以请求城市街区级别的定位精确度,即大约 100 米。这是一个粗略的精确度,消耗的电量可能会比较少。使用此设置,位置信息服务可能会使用 WiFi 和手机信号塔来进行定位。但请注意,位置提供程序的选择还取决于许多其他因素,例如有哪些源可用。
  • PRIORITY_HIGH_ACCURACY - 使用此设置可以请求尽可能准确的定位。使用此设置时,位置信息服务更有可能使用 GPS 来确定位置。
  • PRIORITY_LOW_POWER - 使用此设置可以请求城市级别的定位精确度,即大约 10 公里。这是一个粗略的精确度,消耗的电量可能会比较少。
  • PRIORITY_NO_POWER - 如果您不希望增加功耗,又想及时获得位置更新,请使用此设置。使用此设置时,您的应用不会触发任何位置更新,但会接收其他应用触发的位置更新。

创建位置请求并设置相关参数,如以下代码示例中所示:

Kotlin

    fun createLocationRequest() {
        val locationRequest = LocationRequest.create()?.apply {
            interval = 10000
            fastestInterval = 5000
            priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        }
    }
    

Java

    protected void createLocationRequest() {
        LocationRequest locationRequest = LocationRequest.create();
        locationRequest.setInterval(10000);
        locationRequest.setFastestInterval(5000);
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }
    

将优先级 PRIORITY_HIGH_ACCURACY 与您在应用清单中定义的 ACCESS_FINE_LOCATION 权限设置及 5000 毫秒(5 秒)的快速更新间隔相结合,可让一体化位置信息提供程序返回精确度在几英尺以内的位置更新。这种方法适用于实时显示位置的地图应用。

性能提示:如果您的应用在收到位置更新后访问网络或执行其他长时间运行的工作,请将最快间隔调整为较慢的值。此调整可防止应用收到无法使用的更新。待长时间运行的工作完成后,再重新将最快间隔设置为较快的值。

获得当前位置信息设置

连接到 Google Play 服务和位置信息服务 API 后,即可获得用户设备的当前位置信息设置。要实现此目的,请创建一个 LocationSettingsRequest.Builder,并添加一个或多个位置请求。以下代码段显示了如何添加在上一步中创建的位置请求:

Kotlin

    val builder = LocationSettingsRequest.Builder()
            .addLocationRequest(locationRequest)
    

Java

    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
         .addLocationRequest(locationRequest);
    

接下来,检查是否满足了当前的位置信息设置要求:

Kotlin

    val builder = LocationSettingsRequest.Builder()

    // ...

    val client: SettingsClient = LocationServices.getSettingsClient(this)
    val task: Task<LocationSettingsResponse> = client.checkLocationSettings(builder.build())
    

Java

    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();

    // ...

    SettingsClient client = LocationServices.getSettingsClient(this);
    Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());
    

Task 完成后,应用可以通过查看 LocationSettingsResponse 对象的状态代码来检查位置信息设置。如需了解相关位置信息设置的当前状态的更多详情,您的应用可以调用 LocationSettingsResponse 对象的 getLocationSettingsStates() 方法。

提示用户更改位置信息设置

要确定位置信息设置是否适合位置请求,请将向验证位置信息设置的 Task 对象添加 OnFailureListener。接着,检查传入 onFailure() 方法的 Exception 对象是否是 ResolvableApiException 类的实例,若是,则表示必须更改设置。然后,通过调用 startResolutionForResult() 方法显示一个对话框,请求用户授予修改位置信息设置的权限。

以下代码段展示了如何确定用户的位置信息设置是否允许位置信息服务创建 LocationRequest,以及如何在需要时向用户请求更改位置信息设置的权限:

Kotlin

    task.addOnSuccessListener { locationSettingsResponse ->
        // All location settings are satisfied. The client can initialize
        // location requests here.
        // ...
    }

    task.addOnFailureListener { exception ->
        if (exception is ResolvableApiException){
            // Location settings are not satisfied, but this can be fixed
            // by showing the user a dialog.
            try {
                // Show the dialog by calling startResolutionForResult(),
                // and check the result in onActivityResult().
                exception.startResolutionForResult(this@MainActivity,
                        REQUEST_CHECK_SETTINGS)
            } catch (sendEx: IntentSender.SendIntentException) {
                // Ignore the error.
            }
        }
    }
    

Java

    task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
        @Override
        public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
            // All location settings are satisfied. The client can initialize
            // location requests here.
            // ...
        }
    });

    task.addOnFailureListener(this, new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            if (e instanceof ResolvableApiException) {
                // Location settings are not satisfied, but this can be fixed
                // by showing the user a dialog.
                try {
                    // Show the dialog by calling startResolutionForResult(),
                    // and check the result in onActivityResult().
                    ResolvableApiException resolvable = (ResolvableApiException) e;
                    resolvable.startResolutionForResult(MainActivity.this,
                            REQUEST_CHECK_SETTINGS);
                } catch (IntentSender.SendIntentException sendEx) {
                    // Ignore the error.
                }
            }
        }
    });
    

下一节课接收位置更新将介绍如何接收定期位置更新。