以下纯AI输出
在 Kotlin 的 StateFlow / MutableStateFlow 中,"值相等是否会触发新发射" 是一个常见且重要的机制差异点。下面我们详细说明。
🧩 一、基本结论
MutableStateFlow.value = newValue 时,只有当新旧值不相等 (!= 或 equals() 为 false) 时,才会真正触发新的发射 (emit)。
也就是说:
kotlin
val flow = MutableStateFlow(0)
flow.value = 1 // 会触发一次收集 emit
flow.value = 1 // 不会触发,因为前后相等
⚙️ 二、底层原理简析
StateFlow 的文档中明确说明:
StateFlow is a hot flow that holds a single up‑to‑date value and emits updates only when the value changes.
源码(StateFlowImpl)大致逻辑如下:
kotlin
public override var value: T
set(value) {
if (!areEqual(_state.value, value)) { // 比较是否相等
_state.value = value
notifyCollectors()
}
}
这里的 areEqual(a, b) 实际上是:
kotlin
(a?.equals(b)) == true
即:使用对象的 equals() 进行比较。
🧠 三、对应各种类型的行为
| 类型 | 判等逻辑 | 示例 |
|---|---|---|
Int/String/Boolean 等基本类型 |
值相等 (==) 即不发射 |
1 == 1 → 不发射 |
数据类 data class |
equals() 按内容比较 |
两个内容相同的对象不会触发 |
普通类未重写 equals() |
地址比较 (===) |
即使字段相同但不是同对象,也会触发 |
| 引用类型同一实例 | 地址相同则不发射 |
🧪 四、示例
kotlin
data class Person(val name: String)
val state = MutableStateFlow(Person("Tom"))
// 1️⃣ 相同内容的新对象:equals() == true,不会发射
state.value = Person("Tom") // ❌ 不触发
// 2️⃣ 内容不同:equals() == false,会发射
state.value = Person("Jerry") // ✅ 触发
// 3️⃣ 同一个实例赋值:不会发射
val same = state.value
state.value = same // ❌ 不触发
⚠️ 五、如果你需要"强制发射,即使值相等"
StateFlow 不支持直接这么做;两种方案:
方法 1:使用普通 MutableSharedFlow
MutableSharedFlow 只根据 emit() 调用次数来发射,不会检查相等性:
kotlin
val flow = MutableSharedFlow<Int>(replay = 1)
flow.emit(1) // 发射
flow.emit(1) // 再发射一次,收集端都会收到
方法 2:人为修改对象引用
即便内容一样,但换一个新的实例,就会认为是不同值:
kotlin
state.value = state.value.copy() // equals 一样则仍不触发
state.value = Person(state.value.name + "") // 借助不同引用强制变化
但这种方式不推荐用于语义上"真的没变"的情况。
✅ 小结
| 问题 | 答案 |
|---|---|
| 相同值是否发射? | ❌ 不会 |
| 判等逻辑 | equals() |
| 想强制发射 | 使用 MutableSharedFlow 替代 |
| 优势 | 避免 UI 重复刷新或无意义订阅触发 |
一句话总结:
MutableStateFlow和StateFlow会比较新旧值,相等则不再次发射。需要每次都发射,请用MutableSharedFlow。