MutableStateFlow 强制更新/通知收集器

问题描述

如果更新的值等于旧值 (source)

MutableStateFlow 不会通知收集器。我为此找到了一个 workaround,但它不能很好地适应复杂的值。

解决方法:使用 copy() 复制数据类并使用 toList()/toMutableList() 复制列表。

示例 1:使用变通方法重命名 WorkoutRoutine 的简单数据类 name。这里没有错。

data class WorkoutRoutine(
    var name: String,)

val workoutRoutine = MutableStateFlow(WorkoutRoutine("Initial"))
                                                                                           
workoutRoutine.value.name = "Updated" // Doesn't notify collectors
                                                                                           
workoutRoutine.value = workoutRoutine.value.copy(name = "Updated") // Workaround: works

示例 2:具有多个依赖项的复杂数据类 WorkoutRoutine,使用变通方法Set 添加Exercise 中的 WorkoutRoutine:这需要大量的 {{ 1}} 和 copy() 调用,使代码不可读。

toMutableList()

我尝试了以下方法

  • 添加强制更新 data class WorkoutRoutine( var name: String,var exercises: MutableList<Exercise> = mutablelistof(Exercise()) ) data class Exercise( var sets: MutableList<Set> = mutablelistof(Set()) ) data class Set( var weight: Int? = null ) val workoutRoutine = MutableStateFlow(WorkoutRoutine("Initial")) // Doesn't notify collectors workoutRoutine.value.apply { exercises = exercises.also { it[0].sets.add(Set()) } } // Workaround: works workoutRoutine.value = workoutRoutine.value.copy( exercises = workoutRoutine.value.exercises.toMutableList().also { it[0] = it[0].copy(sets = it[0].sets.apply { add(Set()) }) } ) 的扩展值 MutableStateFlow.valueNotdistinct
    -> 问题:MutableStateFlow.value 必须可以为空
MutableStateFlow.value
  • 使用 var <T> MutableStateFlow<T?>.valueNotdistinct: T? get() = null set(newValue) { value = null value = newValue } ,它不检查相等性
    -> 问题:性能不佳,没有 MutableSharedFlow 属性

我想要的是在每次发出时简单地通知收集器,但我不知道该怎么做,因为 MutableStateFlow 似乎没有“强制通知功能

解决方法

StateFlow 文档说明了这一点:

基于等式的强合并

状态流中的值使用 Any.equals 比较在一个 类似于 distinctUntilChanged 运算符的方式。它用于合并 传入更新 MutableStateFlow 中的值并抑制发射 当新值等于以前的值时收集器的值 发出了一个。使用违反规则的类的状态流行为 Any.equals 的合同未指定。

解决方法可能是覆盖 equals 方法以始终返回 false。因此,数据类对您的情况没有帮助。

class WorkoutRoutine() {
    ...
    override fun equals(other: Any?): Boolean {
        return false
    }    
}