为什么我不能在Kotlin Flow中使用rxJava.Single.create之类的emit函数?

时间:2019-11-22 08:31:42

标签: android kotlin rx-java2 kotlin-coroutines

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

emit

“只能在协程体内调用悬浮功能”。我做错了吗?但我可以在听众之外调用“发出”(在流生成器下面查看)

3 个答案:

答案 0 :(得分:2)

您似乎正在尝试从Android定位服务获取最后一个位置。这是Google Play服务中许多Task回叫电话之一。 Kotlin已经有一个kotlinx-coroutines-play-services模块,可以提供功能

suspend fun <T> Task<T>.await(): T?

在您的项目中,只需编写以下内容即可:

suspend fun getMyLocation(): Location? =
        LocationServices.getFusedLocationProvider(context)
                .lastLocation
                .await()

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

fun <T> Task<T>.asFlow() = flow { emit(await()) }

现在您可以写

fun getLocationAsFlow(): Flow<Location?> =
        LocationServices.getFusedLocationProvider(context)
                .lastLocation
                .asFlow()

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

suspend 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)
}

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

答案 1 :(得分:1)

如Prokash(here)所述,流被设计为自包含的。您的位置服务侦听器不在Flow的范围内。

但是,您可以签出callbackFlow,它为您提供了使用基于回调的API构建流所需的机制。

Callback Flow Documentation,请注意,回调流程仍处于实验阶段。

答案 2 :(得分:0)

基于Coroutines的GitHub页面上的issue

  

流量被设计为自包含,可重播的冷流,因此   超出其自身范围的发射将不属于   合同。

您需要使用Channel之类的替代项来等待currently in developmentConflatedBroadcastChannel