[英]How to skip a Flow and just send last emitted value
我正在開發一個 web 應用程序,以可視化基於 Websockets 的迷宮生成和求解算法。 生成算法實現接口 IMazeGenerator 並返回一個 Flow。
interface IMazeGenerator {
fun generate(maze: Maze): Flow<Maze>
}
在生成器算法的每一步之后,都會發出更新的迷宮。 然后,收集器會在短暫延遲后將中間步驟發送給客戶端。
generatorFlow
.map { it.toDto() }
.delay(150)
.onEach {
client.send(UpdateMaze(it))
}
.launchIn(this.scope)
現在我的問題是:我想為客戶提供跳過中間步驟的可能性,然后只發送最后一個結果,即最終的迷宮。 為此,我首先需要能夠確定發射器是否已經完成(即最終迷宮已經發射),如果是,則在跳過命令到來時僅發送最后一個結果。
不幸的是,我現在根本不知道,我什至不確定這是否適用於流程。 歡迎任何幫助。
您可以創建一個擴展 function 來收集流並返回最后一個元素。 請注意,如果輸入流是無限的,它將無限期暫停。
像這樣的東西:
suspend fun <T> Flow<T>.lastOrNull(): T? {
var elem: T? = null
collect { elem = it }
return elem
}
現在客戶端只需執行val finalMaze = mazeSteps.lastOrNull()
即可獲得最終迷宮。
如果您想將輸入流轉換為只發出最終迷宮的流,您可以這樣做:
fun <T> Flow<T>.skipUntilLast(): Flow<T> = flow {
val last = lastOrNull()
if (last != null) emit(last)
}
謝謝marstran,不幸的是這還沒有直接起作用,但你給了我必要的靈感。 讓我先解釋問題,然后是我的解決方案。
一旦觸發生成,流程就會啟動。 如果客戶端想在某個點之后跳過所有進一步的中間步驟,我需要從這個流中傳輸最后一個發射。 使用您的解決方案,問題是在這種情況下我會重新啟動流程,並獲得不同的結果,因為某些算法是不確定的。 另一個問題是我首先必須確定發射器是否已經計算了最后一個結果,因為某些算法確實需要一些時間。 此時,流程將是可跳過的。 因此,我還必須使用緩沖區來忽略背壓。
我現在創建了一個擴展 function,它在最后一個發出的值上接收一個回調 function。
fun <T> Flow<T>.finalValueCallback(block: suspend (T?) -> Unit) = flow {
var finalValue: T? = null
collect {
emit(it)
finalValue = it
}
block(finalValue)
}
然后我使用這個回調來保存當前流的最后一個結果。 如果出現跳過命令,我會中斷流程並僅發送最后一個結果。
generatorJob = generatorFlow
.onStart { client.send(UpdateGeneratorState(GeneratorState.RUNNING)) }
.map { it.toDto() }
.finalValueCallback {
finalMaze = it
client.send(UpdateGeneratorState(GeneratorState.SKIPPABLE))
}
.buffer()
.delay(150)
.onEach {
client.send(UpdateMaze(it))
}
.onCompletion { cause ->
finalValue = null
if (cause == null || cause is FlowSkippedException) {
client.send(UpdateGeneratorState(GeneratorState.COMPLETED))
} else {
client.send(UpdateGeneratorState(GeneratorState.CANCELLED))
}
}
.launchIn(this.scope)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.