StateFlow、SharedFlow 和LiveData区别

首先出一道题目开始

kotlin 复制代码
class TestActivity : FragmentActivity() {
    val viewModel: TestVM by lazy {
        ViewModelProvider(this).get(TestVM::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.test)
        setupObservers(1)
    }

    override fun onStop() {
        super.onStop()
        viewModel.liveData.value = true
        lifecycleScope.launch {
            viewModel.stateFlow.emit(true)
            viewModel.sharedFlow.emit(true)
            delay(1000L)
            setupObservers(2)
        }
    }

    fun setupObservers(i: Int) {
        viewModel.liveData.observe(this, { it ->
            Log.i("TestModel", "$i liveData observer: $it")
        })

        lifecycleScope.launch {
            viewModel.stateFlow.collect { value ->
                Log.i("TestModel", "$i stateFlow: $value")
            }
        }

        lifecycleScope.launch {
            viewModel.sharedFlow.collect { value ->
                Log.i("TestModel", "$i sharedFlow: $value")
            }
        }
    }
}

class TestVM : ViewModel() {
    val stateFlow = MutableStateFlow(false)
    val sharedFlow =
        MutableSharedFlow<Boolean>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)

    val liveData = MutableLiveData<Boolean>()
}

如上代码所示,进入TestActivity→ 退到后台 → 从后台返回至前台。 你猜日志打印什么?

进入TestActivity

退至后台

后台返回前台

从上面的问题可以得出几个官点:

  1. StateFlow初始化必须要有一个初值,LiveData可有可没有
  2. LiveData只有在可见的时候(onStart→onStop(不包含)),订阅者才能收到值,非可见的时候发生值的变更,只是保存(保存一次),等到可见的时候,才分发给订阅者
  3. 不可见的时候触发值的更新,StateFlow和SharedFlow都会立马回调给观察者,但是LiveData需要变成可见的时候才回调
  4. MutableSharedFlow 可以配置缓存size

LiveData、SharedFlow、StateFlow 的区别

特性 LiveData SharedFlow StateFlow
生命周期感知 ✅ 自动 ❌ 需手动管理 ❌ 需手动管理
必须有初始值 ❌ 可选 ❌ 不需要 ✅ 必须提供
订阅后立即上到上一次值 ✅ 会 ❌ 否 (可配置 (replay)) ✅ 会
多个订阅者 ✅ 支持 ✅ 支持 ✅ 支持
背压处理 ❌ 无 ✅ 可配置缓冲区 ✅ 固定缓冲区(size=1)
线程安全 ✅ 主线程安全 ✅ 协程上下文安全 ✅ 协程上下文安全
数据去重 ❌ 不自动去重 ❌ 不自动去重 ✅ 自动去重
数据发射方式 setValue(), postValue() emit(), tryEmit() emit(), tryEmit()
是否保存状态 ✅ 是 ❌ 否(可配置replay) ✅ 是
观察方式 liveData+lifecycle 协程收集 协程收集
推荐使用场景 简单UI状态更新 一次性事件+使用流式转换 UI状态+使用流式转换

总结

SharedFlow:适用了一次性的事件并且可以使用流式转换

StateFlow: 也是Kotlin官方用来替代LiveData的,因为他支持更复杂的操作,但是Kotlin没有耦合进Android特有的生命周期,无生命周期的感知能力并且需要搭配协程使用。

kotlin 复制代码
//最佳实践
lifecycleScope.launch{
    repeatOnLifeCycle(Lifecycle.State.STARTED){
       stateFlow.collect{ value ->
          textView.text=value
       }
    }
}

使用repeatOnLifeCycle 这样就让stateFlow具备了生命周期感知能力

LiveData: 简单的UI状态更新

大部分情况下使用LiveData就行了,三者使用

思考

为什么MVI 架构中我们看到的使用StateFlow那一套比较多?

1. MVI 想的是「状态是整个界面的唯一真相源」

  • View 不自己存状态。
  • 状态只存在于 ViewModel 的单个对象中。
  • 当你知道这个对象的当前值,你就能100%还原界面。

LiveData 在生命周期变化时,可能自动暂停、延迟派发、自动 re-dispatch,这些"智能操作"会让状态的可预测性下降。 而 StateFlow 不管这些,你自己控制收集时机,所以状态更确定

2.MVI 强调「所有副作用可控、不会重复」

  • LiveData 的"粘性"+"重新变 active 就重新回调"机制,会让你重复执行一次性事件(比如弹两次 Toast)。
  • StateFlow + SharedFlow 明确区分:
    • StateFlow:保存界面状态
    • SharedFlow:发射一次性事件(不会自动重放)

这正符合 MVI 的理念:"状态可重放,副作用不可重放"。
3. MVI 追求「跨平台/可测试的纯逻辑层

LiveData 是 Android 平台的特产(依赖 LifecycleOwnerLooper)。 而 StateFlow 纯 Kotlin 协程实现,既能跑在 Android,也能跑在 JVM/Compose/多平台项目里。

所以在 MVI + Kotlin 协程 体系下,LiveData 显得"多余又限制多"。

相关推荐
TechNomad4 小时前
Kotlin_Lambda编程详解
android·kotlin
熊猫_豆豆5 小时前
QT6 Android C++ 自制美观闹钟
android·c++·qt·闹钟
美狐美颜SDK开放平台5 小时前
Android/iOS直播APP平台开发中的视频美颜SDK优化技巧
android·ios·音视频·美颜sdk·第三方美颜sdk
众人皆醒我独醉7 小时前
Pod 一直 Terminating,死活删不掉?三个凶手,每一个你都意想不到
面试·kubernetes
聚美智数8 小时前
黄历查询-运势查询-国际法定节假日查询-API接口介绍
android·java·数据库
私人珍藏库9 小时前
[Android] 一木百宝箱-万能百宝箱+抖音去水印等几百种功能
android·人工智能·app·软件·多功能
wupa10 小时前
在 enableEdgeToEdge 模式下处理软键盘与自定义面板协同
android
KaifuZeng10 小时前
通信与接口协议面试十、PCIe
单片机·嵌入式硬件·面试·通信与接口协议
三月不知肉味y10 小时前
2026-07-05-JAVA面试场景题训练
java·开发语言·面试
plainGeekDev12 小时前
ProGuard → R8
android·java·kotlin