【Kotlin】StateFlow / MutableStateFlow只有值不相等时才会发射

以下纯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 重复刷新或无意义订阅触发

一句话总结:

MutableStateFlowStateFlow 会比较新旧值,相等则不再次发射。需要每次都发射,请用 MutableSharedFlow

相关推荐
Kapaseker12 小时前
Android 开放这扇门,正在被 Google 从里面反锁
android·kotlin
唐青枫13 小时前
别再把 Util 类堆成杂物间:Kotlin Extension 扩展函数与扩展属性实战详解
kotlin
plainGeekDev1 天前
依赖管理 → Version Catalog
android·java·kotlin
黄林晴2 天前
KMP 正式支持 SwiftPM:CocoaPods 迁移配置指南
android·ios·kotlin
花燃柳卧2 天前
跨平台路由组件工程源码补充上传
android·flutter·kotlin
TechNomad2 天前
Kotlin类对象与接口详解
android·kotlin
Ws_2 天前
Kotlin Multiplatform day2
kotlin
TechNomad3 天前
Kotlin_Lambda编程详解
android·kotlin
plainGeekDev3 天前
ProGuard → R8
android·java·kotlin
aidou13143 天前
Kotlin中沉浸式状态栏显示布局
android·kotlin·windowmanager·沉浸式状态栏·insetslistener·insetscompat·systembars