首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >使用协同服务和EventBus的LiveData实现

使用协同服务和EventBus的LiveData实现
EN

Stack Overflow用户
提问于 2022-03-01 04:44:01
回答 1查看 1.1K关注 0票数 2

我需要在我的应用程序中从不同的地方广播事件,我需要这些事件被不同的ViewModels收听。我所做的是使用Kotlin创建了一个EventBus的“自定义”实现,更具体地说,是Channel。实现如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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中我就这样使用它

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@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

欢迎任何反馈,谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-01 05:51:57

尽管这不是直接回答你的问题.但

为什么需要从流到实时数据的转换?只需订阅ui层上的流,并使用必要的livedata特性填充流。相信我,这会让你的生活更轻松。

我提议使用implementation androidx.lifecycle:lifecycle-runtime-ktx:x.y.zSharedFlow来完成

在片段中

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
with(viewModel) {
    eventsFlow.collectWhenStarted(viewLifecycleOwner, ::processEvents)
}

collectWhenStarted是一种实用的方法,我提供它来简化订阅。它使用库中的launchWhenStarted方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
inline fun <T> Flow<T>.collectWhenStarted(
    lifecycleOwner: LifecycleOwner,
    crossinline action: suspend (T) -> Unit
): Job = lifecycleOwner.lifecycleScope.launchWhenStarted {
    collectLatest {
        action.invoke(it)
    }
}

您可以为其他生命周期事件创建类似的实用程序。

为了代替在配置更改之间持久化数据的LiveData特性,后台/前台的更改只是通过重放将正常的流从域层转换为SharedFlow。在视图模型中

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
val eventsFlow: Flow<DataClass> = flowEventBus
    .flowMessage()
    .shareIn(viewModelScope, SharingStarted.Lazily, 1)

如果您不是distinct,则发出的元素您的EventBus不应该排除传递到那里的任何项。

查看这个文章,这里描述的方法与我建议的方法非常接近

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71308693

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文