如何正确处理位置服务切换
Posted
技术标签:
【中文标题】如何正确处理位置服务切换【英文标题】:How to properly handle location service toggling 【发布时间】:2019-11-26 08:25:00 【问题描述】:在我的应用程序中,我有一个使用FusedLocationProviderClient 获取用户当前位置的按钮。这可以正常工作,直到位置服务关闭然后在设备上重新打开。发生这种情况时,FusedLocationProviderClient.getLastLocation()
总是返回 null。我应该如何处理这种情况?我是否需要以某种方式重新初始化FusedLocationProviderClient
?
我从documentation 了解到,当位置服务关闭时,最后缓存的位置会被刷新。这告诉我我需要强制执行位置请求,以便刷新缓存。但是,我不确定如何做到这一点。我也跟着this Medium article 设置了FusedLocationProviderClient
,但它所做的只是检查位置结果是否为空,当它是时不做任何处理。
我正在用 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)
【问题讨论】:
【参考方案1】:我没有对 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())
上面的 sn-p 设置了一个LocationCallback
,当接收到一个位置时它会被调用。它检查位置(通过isValidLocation
方法),如果它有效,它会从提供程序中删除自己,这样您就不会获得额外的位置更新。在它删除自身的行 (mFusedLocationClient.removeLocationUpdates(this)
) 之后,您可以对 location
对象执行任何您需要执行的工作。如果接收到的位置无效,它会在接收到位置时不断收到额外的回调,直到你得到一个有效的回调。要开始这一切,只需致电watchLocation()
【讨论】:
嗨布拉德利康。您能否解释一下答案中的“完成后删除回调”部分?我已经尝试按照您的建议调用requestLocationUpdates()
,但onLocationResult
回调永远不会被击中。
@ChaseFarmer,我编辑了答案以添加一些示例代码。这有帮助吗?
这很好用!谢谢你为我拼写出来?。我认为我之前的问题是我没有正确初始化LocationRequest
。还在尝试理解 Kotlin 中的代表。以上是关于如何正确处理位置服务切换的主要内容,如果未能解决你的问题,请参考以下文章
切换应用内 GPS UISwitch,当用户切换应用的位置服务时