为什么我不能在 Kotlin Flow 中使用像 rxJava.Single.create 这样的发射函数?

Ili*_*hin 4 android kotlin rx-java2 kotlin-coroutines

我正在尝试将带有 rxjava 链的交互器重写为 kotlin 流。在 LocationHandlerImpl 中,我使用 LocationService 来获取我的当前位置。在 addOnSuccessListener 和 addOnFailureListener 我发出我的模型但有错误:

发射

“只能在协程体内调用暂停函数”。我做错了吗?但是我可以在侦听器之外调用发射(查看流程构建器下方)

Mar*_*nik 6

您似乎正在尝试从 Android 位置服务获取最后一个位置。这是TaskGoogle Play 服务中的许多返回调用之一。Kotlin 已经有一个模块,kotlinx-coroutines-play-services,它提供了一个函数

suspend fun <T> Task<T>.await(): T?
Run Code Online (Sandbox Code Playgroud)

在您的项目中,您可以简单地编写以下内容:

suspend fun getMyLocation(): Location? =
        LocationServices.getFusedLocationProvider(context)
                .lastLocation
                .await()
Run Code Online (Sandbox Code Playgroud)

如果要将其与其他Flow基于代码的代码集成,请添加此包装函数:

fun <T> Task<T>.asFlow() = flow { emit(await()) }
Run Code Online (Sandbox Code Playgroud)

现在你可以写

fun getLocationAsFlow(): Flow<Location?> =
        LocationServices.getFusedLocationProvider(context)
                .lastLocation
                .asFlow()
Run Code Online (Sandbox Code Playgroud)

如果出于教育目的,您想了解如何在没有附加模块的情况下直接实现它,那么最直接的方法如下:

fun getLocationAsFlow() = flow {
    val location = suspendCancellableCoroutine<Location?> { cont ->
        LocationServices.getFusedLocationProvider(context)
                .lastLocation
                .addOnCompleteListener {
                    val e = exception
                    when {
                        e != null -> cont.resumeWithException(e)
                        isCanceled -> cont.cancel()
                        else -> cont.resume(result)
                    }
                }
    }
    emit(location)
}
Run Code Online (Sandbox Code Playgroud)

这是将 的简化实现内联Task.await()到其使用站点的结果。