kotlin 来自多个流的状态对象

dluptydi  于 2023-01-17  发布在  Kotlin
关注(0)|答案(1)|浏览(143)

我需要有一个状态在一个视图模型,得到更新的收集从流。我的State类:

data class DevicesUIState(
    val currentGroup: GroupEntity? = null,
    val currentGroupSubGroups: List<GroupEntity> = listOf(),
    val currentGroupSubDevices: List<DeviceEntity> = listOf(),
    val allDevices: List<DeviceEntity> = listOf(),
)

应从流设置每个属性。流设置currentGroup & allDevices属性不应等待彼此发出结果。流设置currentGroupSubGroups & currentGroupSubDevices取决于所设置的currentGroup。
每个流从房间DB收集
到目前为止,设置状态属性的代码如下所示

val groupId: Int?

val uiState: StateFlow<DevicesUIState> = groupsRepository.groupFlow(groupId)
        .mapLatest {
            Timber.e("Mapping currentGroup")
            DevicesUIState(currentGroup = it)
        }.flatMapLatest { uiState ->
            Timber.e("Mapping currentGroupSubGroups")
            groupsRepository.subGroupsFlow(uiState.currentGroup?.id).map {
                uiState.copy(currentGroupSubGroups = it)
            }
        }.flatMapLatest { uiState ->
            Timber.e("Mapping currentGroupSubDevices")
            liteDeviceRepository.subDevicesFlow(uiState.currentGroup?.id).map {
                uiState.copy(currentGroupSubDevices = it)
            }
        }.flatMapLatest { uiState ->
            Timber.e("Mapping allDevices")
            liteDeviceRepository.allDevicesFlow().map {
                uiState.copy(allDevices = it)
            }
        }.stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5_000L),
            initialValue = DevicesUIState()
        )

它的工作。但看看日志消息的流量收集更多的冒犯,我的预期。所以我有一种感觉,我的代码是不是正确的方式做的事情。
日志

I  --> GET https://example.com/api/groups
E  Mapping currentGroup
E  Mapping currentGroupSubGroups
E  Mapping currentGroupSubDevices
E  Mapping allDevices
I  <-- 200 https://example.com/api/groups (393ms, unknown-length body)
E  Mapping currentGroup
E  Mapping currentGroupSubGroups
E  Mapping currentGroupSubDevices
E  Mapping allDevices
I  --> GET https://example.com/api/devices
I  <-- 200 https://example.com/api/devices (85ms, unknown-length body)
E  Mapping allDevices
I  --> GET https://example.com/api/extraDevicesData
I  <-- 200 https://example.com/api/extraDevicesData (258ms, unknown-length body)
E  Mapping allDevices
n9vozmp4

n9vozmp41#

为了构建这种结构,使彼此不依赖的流可以并行运行,我将对其进行如下更改。
组和依赖于组的两个组可以使用内部combineflatMapLatest来创建。这允许子组或子设备更改,而不会触发其他流的重新启动。
然后,该结果和allDevices流也可以被组合。同样,这允许group和allDevices不触发彼此重启。
抱歉有语法错误。我不是在测试这个。

val uiState: StateFlow<DevicesUIState> = groupsRepository.groupFlow(groupId)
    .flatMapLatest { currentGroup ->
        val id = currentGroup.id
        groupsRepository.subGroupsFlow(id)
            .combine(liteDeviceRepository.subDevicesFlow(id)) { subGroups, subDevices ->
                Timber.e("Combining subGroups and subDevices")
                DevicesUIState(
                    currentGroup = currentGroup,
                    currentGroupSubGroups = subGroups,
                    currentGroupSubDevices = subDevices 
                )
            }
    }.combine(liteDeviceRepository.allDevicesFlow()) { uiState, allDevices ->
        Timber.e("Combining groups and allDevices")
        uiState.copy(allDevices = allDevices)
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5_000L),
        initialValue = DevicesUIState()
    )

如果两个子流经常同时发出新值,您也可以考虑在合并它们之前对它们进行去抖动。

相关问题