我读过类似的主题,但找不到正确的答案:
在我的
Repository
上课我感冒了Flow
我想分享给 2 Presenters
/ViewModels
所以我的选择是使用shareIn
运算符(operator)。让我们看一下 Android 文档的示例:
val latestNews: Flow<List<ArticleHeadline>> = flow {
...
}.shareIn(
externalScope, // e.g. CoroutineScope(Dispatchers.IO)?
replay = 1,
started = SharingStarted.WhileSubscribed()
)
文档对 externalScope
的建议是什么?范围:A CoroutineScope that is used to share the flow. This scope should live longer than any consumer to keep the shared flow alive as long as needed.
但是,寻找有关如何停止订阅
Flow
的答案,第二个链接中投票最多的答案说:A solution is not to cancel the flow, but the scope it's launched in.
对我来说,这些答案在
SharedFlow
中是矛盾的。的情况。不幸的是我的Presenter
/ViewModel
即使在其 onCleared
之后仍会收到最新数据被称为。如何防止这种情况?这是我如何使用
Flow
的示例在我的Presenter
/ViewModel
:fun doSomethingUseful(): Flow<OtherModel> {
return repository.latestNews.map(OtherModel)
如果这可能有帮助,我正在使用 MVI 架构,所以 doSomethingUseful
对用户创建的一些 Intent 使用react。
最佳答案
感谢 Mark Keen 的评论和帖子,我想我设法获得了令人满意的结果。
我了解 shareIn
中定义的范围参数不必与我的消费者操作的范围相同。在 BasePresenter
中更改范围/BaseViewModel
来自 CoroutineScope
至viewModelScope
似乎解决了主要问题。您甚至不需要手动取消此范围,如 Android docs 中所定义。 :
init {
viewModelScope.launch {
// Coroutine that will be canceled when the ViewModel is cleared.
}
}
请记住默认 viewModelScope
调度员是 Main
这并不明显,它可能不是你想要的!要更改调度程序,请使用 viewModelScope.launch(YourDispatcher)
.更何况我的热门
SharedFlow
由另一种寒冷转变而来Flow
创建于 callbackFlow
回调 API(基于 Channels
API - 这很复杂...)将收集范围更改为
viewModelScope
后,我得到 ChildCancelledException: Child of the scoped flow was cancelled
从该 API 发出新数据时出现异常。这个问题在 GitHub 上的两个问题中都有很好的记录:如前所述,使用
offer
的发射之间存在细微差别。和 send
:offer is for non-suspending context, while send is for suspending ones.
offer is, unfortunately, non-symmetric to send in terms of propagated exceptions (CancellationException from send is usually ignored, while CancellationException from offer in nom-suspending context is not).
We hope to fix it in #974 either with offerOrClosed or changing offer semantics
至于 1.4.2 的 Kotlin Coroutines,#974 还没有修复 - 我希望它会在不久的将来避免意外
CancellationException
.最后,我建议玩
started
shareIn
中的参数运算符(operator)。在所有这些更改之后,我不得不从 WhileSubscribed()
更改至Lazily
在我的用例中。如果我发现任何新信息,我会更新这篇文章。希望我的研究能节省一些人的时间。
关于android - Kotlin 流 : unsubscribe from SharedFlow when Fragment becomes invisible,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66267722/