如何正确处理位置服务切换



在我的应用程序中,我有一个按钮,可以使用FusedLocationProviderClient获取用户的当前位置。 在关闭位置服务,然后在设备上重新打开之前,此操作将正常工作。 发生这种情况时,FusedLocationProviderClient.getLastLocation()始终返回 null。 我应该如何处理这种情况? 我是否需要以某种方式重新初始化FusedLocationProviderClient

我从文档中了解到,当位置服务关闭时,最后一个缓存的位置将被刷新。 这告诉我我需要强制位置请求,以便刷新缓存。 但是,我不确定如何做到这一点。 我也按照这篇 Medium 文章来设置FusedLocationProviderClient,但它所做的只是检查位置结果是否为 null,并且在它为空时不做任何处理。

我正在用 Kotlin 编写应用程序。 以下是我初始化FusedLocationProviderClient并在片段中获取用户当前位置的方法:

class LocationFragment : Fragment() {
private lateinit var mFusedLocationProviderClient: FusedLocationProiderClient
override fun onCreate(savedInstanceState: Bundle?) {
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(activity)
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
// Initialize button on-click callback.
}
private fun getCurrentLocation() {
// Check that the location service is enabled.
// Check coarse and fine location permissions.
mFusedLocationProviderClient.lastLocation.addOnSuccessListener {
if (it != null) { // Always false if location services are toggled.
print(it.latitude, it.longitude)
}
}
}
}   

我没有对 FusedLocationProviderClient 做很多事情,但据我了解(文档似乎同意),使用lastLocation(对于 Java 人员来说,getLastLocation())并没有真正出去"获取"当前设备位置,而只是返回设备获取的最后一个位置。通常,设备上任意数量的服务都在请求位置,因此缓存中始终有一个相当准确的值供lastLocation使用。但是,如果您关闭并重新打开定位服务,然后立即呼叫lastLocation,您很可能会返回null。另请注意,lastLocation的文档指出:

它特别适用于不需要精确定位的应用

getLocationAvailability()电话的文档中:

请注意,getLastLocation() 总是有可能返回 null,即使此方法返回 true(例如,在调用之间禁用了位置设置)。

这些也证实了该方法实际上并不执行位置查找,而只是从缓存中返回最新的查找,并且当您关闭/打开服务时,缓存为空。

如果需要确保获取设备的当前位置并确保它相当准确,则可能需要使用requestLocationUpdates()让位置客户端实际找出设备的当前位置并在您提供的回调中返回它,然后在完成后删除回调。

自从我与位置提供商合作以来已经有一段时间了,但我认为您可以做这样的事情,假设您只需要一个位置:

private val locationRequest: LocationRequest by lazy {
LocationRequest.create().apply {
interval = (LOCATION_UPDATE_INTERVAL_SECONDS * 1000).toLong()
fastestInterval = (LOCATION_FAST_INTERVAL_SECONDS * 1000).toLong()
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
smallestDisplacement =
MINIMUM_DISPLACEMENT_METERS
}
}
private fun isValidLocation(location: Location): Boolean {
/* TODO: validate that the location meets all of your
requirements for accuracy, etc, and return the
appropriate true/false value
*/
return true  // or false, for example if the location accuracy is not good enough.    
}    

private val locationCallback = object: LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
Log.d(TAG, "Location Received: $locationResult")
val location = locationResult.lastLocation
if (isValidLocation(location)) {
Log.d(TAG, "Valid Location dectected: $location")
// we have a valid location, so stop receiving further location updates.
mFusedLocationClient.removeLocationUpdates(this)
//TODO: we have a valid location! Use it as you wish to update the
//      view, or emit it via a LiveData, etc.
} else {
// nothing to do, wait for more results.
Log.d(TAG, "Location received was not valid: $location")
}
}
}    
private fun watchLocation() {
// Check Location Permissions
// Check Google Play Services Version
// Check Location Settings
// If all three are good, then:
mFusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())
} 

上面的代码片段设置了一个在收到位置时调用的LocationCallback。它检查位置(通过isValidLocation方法),如果有效,它会从提供程序中删除自身,以便您不会获得其他位置更新。紧跟在它删除自身的行(mFusedLocationClient.removeLocationUpdates(this))之后,你可以对location对象做任何你需要做的工作。如果收到的位置无效,它将在收到位置时不断收到其他回调,直到您获得有效的位置。要开始这一切,只需致电watchLocation()

最新更新