FusedLocationProviderClient与Kotlin协同程序

问题描述 投票:1回答:2

我正在尝试使用FusedLocationProviderClient和Kotlin Coroutines请求一个新位置。这是我目前的设置:

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())这不是说我只能调用一次这个函数吗?

任何帮助表示赞赏。

android kotlin fusedlocationproviderapi kotlin-coroutines
2个回答
1
投票

你已经设置了你的coroutineContext错了。你应该有

override val coroutineContext = Dispatchers.MAIN + job

如果您需要IO调度程序,请明确要求:

withContext(Dispatchers.IO) { ... blocking IO code ... }

要暂停协程,请调用suspendCancellableCoroutine,否则您将无法从结构化并发中获益。

另一个细节,不要在it.resume块中的suspendCancellableCoroutine之后写任何代码。如果调度程序选择立即恢复协程,则在resume调用内,该代码将不会执行,直到协程的所有代码都已运行(或至少直到下一个暂停点)。

override fun onLocationResult(result: LocationResult) {
    fusedLocationProviderClient.removeLocationUpdates(this)
    it.resume(result.lastLocation.run { latitude at longitude })
}

1
投票

通过使用suspendCoroutine,您可以在调度程序上调用提供的代码,该代码在运行时调用suspeted函数。由于大多数调度员不在Looper线程上运行(几乎只有Dispatchers.MAIN),因此对Looper.myLooper()的调用失败。

文档说你可以用Looper.myLooper()替换null来调用未指定线程上的回调。然后,内置的协程调度程序将确保将其路由到正确的线程以恢复执行。

编辑:您可能需要调用it.intercepted().resume(latLng)以确保将结果分派到正确的线程。我不完全确定suspendCoroutine延续是否在默认情况下被截获。

此外,您不需要调用fusedLocationProviderClient.removeLocationUpdates(this),因为您已经将LocationRequest中的更新数量设置为1

© www.soinside.com 2019 - 2024. All rights reserved.