android - SingleLiveEvent 带 Buffer 和协程
问题描述
我想构建一个SingleLiveEvent的替代品,其中有一个缓冲区,以避免在旧事件被消耗之前出现新事件时丢失事件。
目标是拥有一个发出事件的 Android ActivityViewModel,以及使用这些事件的几个片段。这意味着当一个片段被销毁时,它会停止订阅,而当一个对这些事件感兴趣的新片段开始时,它应该订阅它。换句话说,应该可以有 0、1 或更多的订阅者。
我正在尝试使用以下代码使用 kotlin 协程通道来构建它。在发出事件的 ActivityViewModel 中:
val userEvent = Channel<UserEvent>(Channel.UNLIMITED)
suspend fun onUserEvent(event: UserEvent) {
userEvent.send(event)
}
在应该订阅的片段中:
override fun onCreateView(...) {
(...)
lifecycleScope.launchWhenStarted {
sharedViewModel.userEvent.consumeEach {
// do something with event
}
}
}
我面临的问题是片段消耗了这些事件,但是每当取消其范围时,通道也会被取消。然后另一个片段订阅,当 ActivityViewModel 尝试send
它崩溃时,JobCancellationException
因为userEvent.isClosedForSend
是真的。
如果我改用 GlobalScope.launch,它不会被取消。但是后来我失去了生命周期处理(开始后开始订阅,销毁后取消)。
那么,我怎样才能保持通道打开并仍然处理生命周期呢?有没有更好的方法来做到这一点?
解决方案
我也在使用提到的答案,然后我意识到当用户快速浏览应用程序时它会记住以前的事件。我的解决方案是这样的:
private val _effect = Channel<CurrenciesEffect>(1)
val effect = _effect.receiveAsFlow().conflate()
在片段中
private fun observeEffect() = lifecycleScope.launchWhenStarted {
currenciesViewModel.effect.collect { viewEffect ->
...
}
}
推荐阅读
- hdf5 - 是否可以复制整个 hdf5 文件并使用 h5copy 扩展外部链接?
- django - Django zip 使用 xhtml2pdf 生成的多个 PDF 文件
- vba - 用于在另一张表中查找单元格数据并更新它的 VBA 代码
- wordpress - docker-compose 在安装 wordpress 时锁定我的本地文件夹
- r - 当我在 R 中使用 Rcpp 时,包含 boost 的编译错误
- nginx - 用于 SEO 的 nginx 条件预渲染页面(if + try_files)
- android - Android 媒体播放器、数据源 api、三星 s8+
- android - Android 启动画面显示在系统栏后面
- glsl - GLSL 问题:坐标偏移和后退在不同的机器上产生不同的结果
- c++ - 中间部分不同的两个功能如何组织