我需要在我的应用程序中从不同的地方广播事件,我需要这些事件被不同的ViewModels收听。我所做的是使用Kotlin创建了一个EventBus的“自定义”实现,更具体地说,是Channel
。实现如下所示:
interface FlowEventBus {
sealed class MessageEvent {
data class MessageA(
val someData: Int
) : MessageEvent()
data class MessageB(
val someOtherData: String
) : MessageEvent()
object MessageC : MessageEvent()
}
suspend fun postMessage(messageEvent: MessageEvent)
fun flowMessage(): Flow<MessageEvent>
}
class FlowEventBusImpl() : FlowEventBus {
private val channel = Channel<FlowEventBus.MessageEvent>()
override suspend fun postMessage(messageEvent: FlowEventBus.MessageEvent) {
channel.send(messageEvent)
}
override fun flowMessage(): Flow<FlowEventBus.MessageEvent> {
return channel.receiveAsFlow()
}
}
然后在我的ViewModels中我就这样使用它
@HiltViewModel
class SomeViewModel @Inject constructor(
private val flowEventBus: FlowEventBus
) : ViewModel() {
val message = flowEventBus.flowMessage().asLiveData()
// ...
这样做的想法是,无论Activity
还是Fragment
使用这个ViewModel,他们都可以观察message
属性并对"EventBus“事件做出反应。
,怎么了?
其中一些事件是不可靠的。例如,假设ActivityA
正在观察messages
,每次我们得到MessageC
事件时它都会提示Snackbar
。如果FlowEventBus
广播一个MessageC
事件两次,我们只会看到Snackbar
弹出一次。我对Kotlin还不太了解,我认为可能发生的是类SingleLiveEvent
场景。我的猜测是,asLiveData()
扩展将Flow
转换为MutableLiveData
,如果我们两次设置相同的值,它就会忽略它。但我不知道如何在这里介绍SingleLiveEvent
。
欢迎任何反馈,谢谢!
发布于 2022-03-01 05:51:57
尽管这不是直接回答你的问题.但
为什么需要从流到实时数据的转换?只需订阅ui层上的流,并使用必要的livedata特性填充流。相信我,这会让你的生活更轻松。
我提议使用implementation androidx.lifecycle:lifecycle-runtime-ktx:x.y.z
和SharedFlow
来完成
在片段中
with(viewModel) {
eventsFlow.collectWhenStarted(viewLifecycleOwner, ::processEvents)
}
collectWhenStarted
是一种实用的方法,我提供它来简化订阅。它使用库中的launchWhenStarted
方法:
inline fun <T> Flow<T>.collectWhenStarted(
lifecycleOwner: LifecycleOwner,
crossinline action: suspend (T) -> Unit
): Job = lifecycleOwner.lifecycleScope.launchWhenStarted {
collectLatest {
action.invoke(it)
}
}
您可以为其他生命周期事件创建类似的实用程序。
为了代替在配置更改之间持久化数据的LiveData
特性,后台/前台的更改只是通过重放将正常的流从域层转换为SharedFlow
。在视图模型中
val eventsFlow: Flow<DataClass> = flowEventBus
.flowMessage()
.shareIn(viewModelScope, SharingStarted.Lazily, 1)
如果您不是distinct
,则发出的元素您的EventBus不应该排除传递到那里的任何项。
查看这个文章,这里描述的方法与我建议的方法非常接近
https://stackoverflow.com/questions/71308693
复制相似问题