Kotlin Flow:如何退订/停止

时间:2019-07-18 06:38:50

标签: kotlin kotlin-coroutines

我有一个流发出多个字符串:

int smallest_element = *min_element(vec.begin(),vec.end());

一段时间后,我想退订该流。目前,我正在执行以下操作:

@FlowPreview
suspend fun streamTest(): Flow<String> = flowViaChannel { channel ->
    listener.onSomeResult { result ->
            if (!channel.isClosedForSend) {
                channel.sendBlocking(result)
            }
    }
}

如果协程被取消,该流仍将执行。没有订阅者在听新值。如何退订并停止viewModelScope.launch { beaconService.streamTest().collect { Timber.i("stream value $it") if(it == "someString") // Here the coroutine gets canceled, but streamTest is still executed this.cancel() } } 功能?

4 个答案:

答案 0 :(得分:2)

解决方案不是取消流程,而是取消其启动范围。

val job = scope.launch { flow.collect { } }
job.cancel()

答案 1 :(得分:2)

您可以在 Flow 上使用 takeWhile 运算符。

flow.takeWhile { it != "someString" }.collect { emittedValue ->
         //Do stuff until predicate is false  
       }

答案 2 :(得分:1)

当流在 courtin 范围内运行时,您可以从中获取作业以控制停止订阅。

// Make member variable if you want.
var jobForCancel : Job? = null

// Begin collecting
jobForCancel = viewModelScope.launch {
    beaconService.streamTest().collect {
        Timber.i("stream value $it")
        if(it == "someString")
            // Here the coroutine gets canceled, but streamTest is still executed
            // this.cancel() // Don't
    }
}

// Call whenever to canceled
jobForCancel?.cancel()

答案 3 :(得分:0)

使用协程的当前版本/ Flows(1.2.x),我现在不是一个好的解决方案。借助onCompletion,您将在流程停止时得到通知,但随后您将无法使用streamTest函数,因此很难停止监听新事件。

beaconService.streamTest().onCompletion {

}.collect {
    ...
}

有了协程的下一个版本(1.3.x),这将非常容易。不推荐使用功能flowViaChannel,而推荐使用channelFlow。此功能使您可以等待流关闭并在此时进行一些操作,例如。删除监听器:

channelFlow<String> {
    println("Subscribe to listener")

    awaitClose {
        println("Unsubscribe from listener")
    }
}