StateFlow 的使用

0 阅读2分钟

一、StateFlow 是什么?

  • 属于 Kotlin 协程 Flow 体系
  • 粘性可观察状态持有者
  • 永远持有最新一个状态
  • 新订阅者会立刻收到当前最新值
  • 适合:页面 UI 状态管理(MVVM、MVI)
  • 线程安全、适合跨协程使用

二、StateFlow 两种类型

1. MutableStateFlow(内部可写)

kotlin

private val _uiState = MutableStateFlow(UiState())
  • 只在 ViewModel 内部使用
  • 可以修改值、更新状态

2. StateFlow(外部只读)

kotlin

val uiState: StateFlow<UiState> = _uiState.asStateFlow()
  • 暴露给 Fragment/Activity
  • 只能观察,不能修改
  • 保证安全、单向数据流

三、定义步骤(标准模板)

1. 定义状态(必须是 data class)

kotlin

data class UiState(
    val isLoading: Boolean = false,
    val data: String? = null,
    val error: String? = null
)

2. ViewModel 里创建

kotlin

class MyViewModel : ViewModel() {
    // 可变(内部)
    private val _uiState = MutableStateFlow(UiState())
    
    // 只读(外部)
    val uiState: StateFlow<UiState> = _uiState.asStateFlow()
}

3. 界面收集(观察)

kotlin

lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.uiState.collect { state ->
            // 更新UI
            tv.text = state.data
        }
    }
}

四、更新 StateFlow 的 5 种方法(最重要)

1. update {...} —— 最推荐、线程安全

基于旧值生成新值,原子操作、并发安全

kotlin

_uiState.update { it.copy(isLoading = true) }

2. value = 直接赋值

适合不依赖旧值的覆盖更新非原子,多协程不安全

kotlin

_uiState.value = UiState(isLoading = true)

3. getAndUpdate { ... }

原子更新,返回更新前的值

kotlin

val oldState = _uiState.getAndUpdate { it.copy(isLoading = true) }

4. updateAndGet { ... }

原子更新,返回更新后的值

kotlin

val newState = _uiState.updateAndGet { it.copy(isLoading = true) }

5. compareAndSet(expect, newValue)

底层原子方法,手动判断更新

kotlin

_uiState.compareAndSet(oldValue, newValue)

五、方法对比表(必背)

方法线程安全原子基于旧值返回值推荐度
updateUnit⭐⭐⭐⭐⭐
value =Unit⭐⭐
getAndUpdate旧值⭐⭐⭐⭐
updateAndGet新值⭐⭐⭐⭐
compareAndSetBoolean⭐⭐⭐

六、为什么必须用 copy ()?

因为:StateFlow 比较引用,不比较内容

kotlin

// 正确:创建新对象
it.copy(isLoading = true)

// 错误:对象没变,UI 不刷新
it.isLoading = true

copy () 作用:

  • 复制一个新对象
  • 只改你指定的字段
  • 其他字段自动保留

七、StateFlow vs SharedFlow(高频面试)

特性StateFlowSharedFlow
存储数据只存最新 1 个可存多个缓冲
粘性✅ 新订阅收当前值可配置
初始值必须给不需要
用途UI 状态管理事件通知
去重相同值不会发射不会去重

八、最佳实践(公司标准规范)

1. 状态必须用 data class

kotlin

data class UiState(...)

2. 私有可变,公开只读

kotlin

private val _uiState = MutableStateFlow(...)
val uiState = _uiState.asStateFlow()

3. 更新状态必须用 update

kotlin

_uiState.update { it.copy(xxx = xxx) }

4. 界面收集必须用:

kotlin

repeatOnLifecycle(Lifecycle.State.STARTED)

5. 不要在 StateFlow 存:

  • Activity / Context
  • View
  • 非数据类(容易内存泄漏)

九、常见坑(90% 的人都踩过)

❌ 错误 1:不使用 copy () → UI 不刷新

kotlin

// 不生效
_uiState.value.isLoading = true

❌ 错误 2:直接暴露 MutableStateFlow

kotlin

// 不安全!外部可随便改
val uiState = MutableStateFlow(...)

❌ 错误 3:不用 repeatOnLifecycle 导致内存泄漏

kotlin

// 错误
lifecycleScope.launch { ... }

// 正确
repeatOnLifecycle(STARTED) { ... }

❌ 错误 4:多协程并发用 value =

kotlin

// 线程不安全
_uiState.value = _uiState.value.copy(...)

十、一句话终极总结

StateFlow = 持有最新状态的安全可观察对象

update () + copy () = 标准更新方式

只读暴露 + repeatOnLifecycle = 标准使用方式