将 MediatorLiveData 迁移到 SharedFlow

Ten*_*r04 7 android kotlin android-room kotlin-coroutines kotlin-coroutines-flow

我有一个使用三个 LiveData 源的 MediatorLiveData。当它们中的任何一个发出一个新值并且我至少有一个值时,我使用这三个值来生成 UI 的输出。

其中两个来源是关于如何对列表进行排序和过滤的用户设置,第三个是从 Room 数据库 Flow 中提取的列表数据。

它看起来像这样:

val thingsLiveData: LiveData<List<Thing>> = object: MediatorLiveData<List<Thing>>() {
    var isSettingA: Boolean = true
    var settingB: MySortingEnum = MySortingEnum.Alphabetical
    var data: List<Thing>? = null
    init {
        addSource(myRepo.thingsFlow.asLiveData()) {
            data = it
            dataToValue()
        }
        addSource(settingALiveData) {
            isSettingA= it
            dataToValue()
        }
        addSource(settingBLiveData) {
            settingB= it
            dataToValue()
        }
    }
    private fun dataToValue() {
        data?.let { data ->
            viewModelScope.launch {
                val uiList = withContext(Dispatchers.Default) {
                    produceUiList(data, isSettingA, settingB)
                }
                value = listItems
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种干净的方法将其转换为 SharedFlow,最好没有任何@ExperimentalCoroutinesApi. 我遇到的唯一 SharedFlow 构建器函数是callbackFlow,它不适用。您是否打算flow { ... }.asSharedFlow(...)在大多数情况下使用,如果是这样,这里会是什么样子?

这两个设置 LiveData 我还计划迁移到流。

Ten*_*r04 9

可以使用 组合源流combine(),这会创建一个冷流,在收集时,将开始从其源流收集,该源流可能是热的,也可能是冷的。

我原本以为我一定错过了一些东西,应该有某种方法可以直接将热流组合成组合热流。但我意识到,操作员应该只返回冷流,并让您自行将其转换回热流(如果您需要的话),这是有道理的。

在很多情况下,比如我的,把它放冷就完全没问题了。我只从 UI 中的一个位置收集此 Flow,因此仅在收集时才开始组合源并不重要。源热流并不关心当前是否有东西正在收集它们......它们只是继续发射。

如果我从多个地方或多次收集此流,那么shareIn在组合流上使用它以使其热可能是有意义的,这将避免组合源的冗余工作。潜在的缺点是,即使没有收集任何数据,它也会合并这些来源,这将是浪费工作。

val thingsFlow: Flow<List<Thing>> = combine(
    myRepo.thingsFlow,
    settingALiveData.asFlow(),
    settingBLiveData.asFlow()
) { data, isSettingA, settingB -> produceUiList(data, isSettingA, settingB) }

// where produceUiList is now a suspend function that wraps 
// blocking code using withContext
Run Code Online (Sandbox Code Playgroud)