MutableStateFlow
不会通知收集器更新后的值是否等于旧值(源(。我已经找到了一个解决方法,但它不能很好地适应复杂的值。
解决方法:使用copy()
复制数据类,使用toList()
/toMutableList()
复制列表。
示例1:使用变通方法重命名name
的简单数据类WorkoutRoutine
。这里没什么问题。
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
添加到WorkoutRoutine
中的Exercise
:这需要大量的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.value
的扩展值MutableStateFlow.valueNotDistinct
->问题:MutableStateFlow.value
必须可以为null
var <T> MutableStateFlow<T?>.valueNotDistinct: T?
get() = null
set(newValue) {
value = null
value = newValue
}
- 使用不检查相等性的
MutableSharedFlow
->问题:没有性能,没有value
属性
我想要的只是在每次发射时简单地通知收集器,但我不知道如何做到这一点,因为似乎没有"强制通知";函数
StateFlow文档指出:
基于强相等的合并
状态流中的值在类似于distinctUntilChanged运算符。它被用来混淆传入更新MutableStateFlow中的值并抑制发射当新值等于以前的发射了一个。具有违反Any.equals的合同未指明。
解决方法可以重写equals
方法以始终返回false
。因此,数据类对您的情况没有帮助。
class WorkoutRoutine() {
...
override fun equals(other: Any?): Boolean {
return false
}
}
MutableStateFlow
只是一个接口,所以如果你不喜欢默认实现的工作方式,你可以自己编写。这里有一个简单的实现,它使用MutableSharedFlow
来支持它。它不进行比较,所以它总是会更新。
class NoCompareMutableStateFlow<T>(
value: T
) : MutableStateFlow<T> {
override var value: T = value
set(value) {
field = value
innerFlow.tryEmit(value)
}
private val innerFlow = MutableSharedFlow<T>(replay = 1)
override fun compareAndSet(expect: T, update: T): Boolean {
value = update
return true
}
override suspend fun emit(value: T) {
this.value = value
}
override fun tryEmit(value: T): Boolean {
this.value = value
return true
}
override val subscriptionCount: StateFlow<Int> = innerFlow.subscriptionCount
@ExperimentalCoroutinesApi override fun resetReplayCache() = innerFlow.resetReplayCache()
override suspend fun collect(collector: FlowCollector<T>): Nothing = innerFlow.collect(collector)
override val replayCache: List<T> = innerFlow.replayCache
}
将MutableStateFlowsupdate
函数与数据类copy
函数结合使用,可以安全地更新StateFlow:
data class WorkoutRoutine(
var name: String,
var exercises: List<Exercise> = emptyList()
)
data class Exercise(
var sets: List<Set> = emptyList()
)
data class Set(
val weight: Int? = null
)
val workoutRoutine = MutableStateFlow(WorkoutRoutine("Initial"))
// Doesn't notify collectors
workoutRoutine.update { currentState ->
currentState.copy(
exercises = (currentState.exercises.firstOrNull()?.sets ?: emptyList()) + Set()
}
}