我正在尝试使用FusedLocationProviderClient和Kotlin协同程序请求新位置。这是我的当前设置:
class LocationProviderImpl(context: Context) : LocationProvider, CoroutineScope {
private val TAG = this::class.java.simpleName
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.IO
private val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
private val locationRequest = LocationRequest().apply {
numUpdates = 1
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
override suspend fun getLocation(): LatLng = suspendCoroutine {
val locationCallback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
result.lastLocation.run {
val latLng = latitude at longitude
it.resume(latLng)
}
fusedLocationProviderClient.removeLocationUpdates(this)
}
}
try {
fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())
} catch (e: SecurityException) {
throw NoLocationPermissionException()
}
}
}
但在尝试请求新位置时,我得到以下异常:
java.lang.IllegalStateException: Can't create handler inside thread that has not called Looper.prepare()
然而,如果我调用Looper.prepare()(最终调用Looper.quit()),这是否意味着我只能调用该函数一次?
任何帮助都是感激不尽的。
3条答案
按热度按时间y1aodyip1#
问题出在您设定
coroutineContext
的方式上。请改用下列方式:如果需要
IO
调度程序,可以显式地要求它:要暂停协程,请调用
suspendCancellableCoroutine
,否则您将无法从结构化并发中获得任何好处。另一个细节是,不要在
suspendCancellableCoroutine
块中的it.resume
之后写任何代码。如果调度程序选择立即恢复协程,在resume
调用中,该代码将不会执行,直到协程的所有代码都运行完(或者至少直到下一个挂起点)。0md85ypi2#
hwazgwia3#
通过使用
suspendCoroutine
,您可以在运行时调用挂起函数的调度程序上调用提供的代码。由于大多数调度程序不在循环线程上运行(几乎只有Dispatchers.MAIN
在循环线程上运行),因此对Looper.myLooper()
的调用失败。文档中说你可以用
null
代替Looper.myLooper()
来调用一个未指定线程上的回调函数,然后内置的协程调度器会确保它被路由到正确的线程以恢复执行。编辑:你可能需要调用
it.intercepted().resume(latLng)
来确保结果被分派到正确的线程。我不完全确定suspendCoroutine
的延续是否被默认拦截。此外,您不需要调用
fusedLocationProviderClient.removeLocationUpdates(this)
,因为您已经将LocationRequest
中的更新次数设置为1
。