繁体   English   中英

取消 Kotlin 流程的收集

[英]Cancelling the collect of the Kotlin flow

我有一个具有不同状态的父类,这个父类有一个子类列表,每个子类都有不同的状态。 我想收集它们中的每一个并取消达到Terminated状态的那个。 类似的东西:

coroutineScope.launch(Dispatcher.IO) {
   parent.parentState.collect {
      if(it is ParentState.Normal){
         it.children.forEach{ child ->
             coroutineScope.launch(Dispatcher.IO){
                child.childState.collect{
                    if(it is ChildState.Terminated){
                       //when this line executed all the collectors stop until I change the states for each one of them..
                       this.coroutineContext.job.cancel()
                    } else{
                       // Do something else for any other state...
                    }
                }
             }

         }
      }
   }
}

但是当我这样做时,我正在收集的所有孩子都停止收集,但它又开始收集如果我改变了每个孩子的状态,在取消其中一个之前不是这种情况。

所以我的问题是为什么在取消其中一位收藏家的工作时会出现这种情况?

还有没有更好的“反应方式”来写这个?

默认情况下,协程作用域在CoroutineContext使用Job()Job()将取消协程执行或取消任何正在运行的子进程或抛出异常。

为了保持其他子执行保持活动状态,您可以使用特殊的Job ,即SupervisorJob()

CoroutineScope(SupervisorJob() + Dispatchers.IO)

因此,您的代码将如下所示

val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
   parent.parentState.collect {
      if(it is ParentState.Normal){
         it.children.forEach{ child ->
             coroutineScope.launch(Dispatcher.IO){
                child.childState.collect{
                    if(it is ChildState.Terminated){
                       //when this line executed all the collectors stop until I change the states for each one of them..
                       this.coroutineContext.job.cancel()
                    } else{
                       // Do something else for any other state...
                    }
                }
             }

         }
      }
   }
}

我完全同意你可以使用SupervisorJob来处理你的问题。

但在我看来,不需要那么多子工作。 一个子任务可以解决你遇到的问题。 在您的代码中,将创建一个大小为children Collection的子协程。 虽然协程很轻量级,但我认为这是不必要的开销。

您可以在每个Flow collect之前将List<Flow<T>>完全转换为Flow<List<T>> 之后,只能collect转换后的单个Flow

这是我的处理方式:

inline fun <reified T> List<Flow<T>>.flattenFlow(): Flow<List<T>> = combine(this@flattenFlow) {
    it.toList()
}

coroutineScope.launch(Dispatcher.IO) {
    parent.parentState.collect {
        if (it is ParentState.Normal) {
            it.flattenFlow().collect {childStateList ->
                childStateList.onEach {childState ->
                    if (childState is ChildState.Terminated) {
                        // Do something when state in Terminated..
                    } else {
                        // Do something else for any other state...
                    }
                }
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM