Android Kotlin(五)数据流StateFlow和LiveData

Android 上的 Kotlin 数据流

在协程中,与仅返回单个值的挂起函数相反,数据流可按顺序发出多个值。数据流以协程为基础构建,可提供多个值。从概念上来讲,数据流是可通过异步方式进行计算处理的一组数据序列。所发出值的类型必须相同。

来源标注:Android 上的 Kotlin 数据流 | Android Developers

书接上篇:

Android Kotlin知识汇总(二)最佳实践-CSDN博客Android Jetpack之LiveData 使用及源码_android livedata源码-CSDN博客Android Kotlin知识汇总(二)最佳实践-CSDN博客


Kotlin中StateFlow的使用

在 Android 中,StateFlow 非常适合需要让可变状态保持可观察的类。

StateFlow 是 Flow 的实现。默认的 Flow 是冷流,而StateFlow 是热流和 LiveData 类似。

使用 StateFlow 替代 LiveData 应该是目前很多开发者的呼吁了,确实 LiveData 的功能 StateFlow 都能实现,可以说是 LiveData 的升级版。

但请注意,StateFlowLiveData 的行为确实有所不同:

  • StateFlow 需要将初始状态传递给构造函数,而 LiveData 不需要。
  • 当 View 进入 STOPPED 状态时,LiveData.observe() 会自动取消注册使用方,而从 StateFlow 或任何其他数据流收集数据的操作并不会自动停止。

StateFlow的特点

  • 它始终是有值的。
  • 它的值是唯一的。
  • 它允许被多个观察者共用 (因此是共享的数据流)。
  • 它永远只会把最新的值重现给订阅者,这与活跃观察者的数量是无关的。

StateFlow的设计

StateFlow是一种单数据更新的热流,通过emit方法更新StateFlow的数据,通过value属性可以获取当前的数据。

设计中,关键讲一下MutableStateFlow接口。它接口继承自StateFlow接口,并在此基础上定义了一个新方法compareAndSet, 即通过CAS的方式更新value。代码如下:

Kotlin 复制代码
public interface MutableStateFlow<T> : StateFlow<T>, MutableSharedFlow<T> {
    // 当前数据
    public override var value: T
    // 如果except与value相等,则将value更新为update,并返回true
    // 如果except与value不相等,不做任何操作,直接返回false
    public fun compareAndSet(expect: T, update: T): Boolean
}

StateFlow的使用

方式一

在Activity中像类似LiveData 一样的使用 StateFlow。

Kotlin 复制代码
class DemoViewModel @Inject constructor(val savedState: SavedStateHandle) : BaseViewModel() {
    private val _searchFlow = MutableStateFlow("")
    val searchFlow: StateFlow<String> = _searchFlow
    fun changeSearch(keyword: String) {
        _searchFlow.value = keyword
    }
}
private fun testflow() {
    mViewModel.changeSearch("key")
}
override fun startObserve() {
   lifecycleScope.launchWhenCreated {
       mViewModel.searchFlow.collect {
         LogUtils.w("value $it")
       }
   }
}

方式二

通过一个 冷流 Flow 转换为 StateFlow 。

Kotlin 复制代码
val stateFlow = flowOf(1, 2, 3).stateIn(
      scope = lifecycleScope,
      started = Lazily,
      initialValue = 1
)
lifecycleScope.launch {
      stateFlow.collect {}
}

LiveData 与 StateFlow对比

先看看它们的代码的用法。

Kotlin 复制代码
class DemoViewModel @Inject constructor(val savedState: SavedStateHandle) : BaseViewModel() {
    private val _searchLD = MutableLiveData<String>()
    val searchLD: LiveData<String> = _searchLD

    private val _searchFlow = MutableStateFlow("")
    val searchFlow: StateFlow<String> = _searchFlow

    fun changeSearch(keyword: String) {
        _searchFlow.value = keyword
        _searchLD.value = keyword
    }
}

Activity中触发与接收事件:

Kotlin 复制代码
private fun testflow() {
    mViewModel.changeSearch("key")
}
override fun startObserve() {
   mViewModel.searchLD.observe(this){
     LogUtils.w("value $it")
   }

   lifecycleScope.launchWhenCreated {
     mViewModel.searchFlow.collect {
      LogUtils.w("value $it")
     }
   }
}

可以看到,代码使用上十分类似。

LiveData的缺点

  • LiveData在某些特定的场景下会丢失数据
  • LiveData 只能在主线程不能方便地支持异步化
  • LiveData 的数据变换能力远远不如 Flow
  • LiveData 粘性问题解决需要额外扩展
  • LiveData 多数据源的合流能力远远不如 Flow
  • LiveData 默认不支持防抖,值没有变化也会通知

两者在开发中如何选择呢?

  • 团队内全部是Koltin代码开发,推荐使用Flow。因为基于Kotlin代码、基于协程。但是现在很多项目还是 Java 语言开发的。那么LiveData还是很香的。
  • LiveData的学习成本与协程、Flow 的学习成本不可同日而语,开发项目是整个团队的事情,不能说你一个人会一个人用,目前LiveData的简单学习成本是很有优势的。

注意:特定的场景慎重使用postValue。比如数据密集的场景,尽量使用setValue方法。

相关推荐
律品1 分钟前
pytest的前置与后置
开发语言·python·pytest
雨白12 分钟前
OkHttpClient 核心配置详解
android·okhttp
淡淡的香烟14 分钟前
Android auncher3实现简单的负一屏功能
android
山中月侣42 分钟前
Java多线程编程——基础篇
java·开发语言·经验分享·笔记·学习方法
RabbitYao1 小时前
Android 项目 通过 AndroidStringsTool 更新多语言词条
android·python
RabbitYao1 小时前
使用 Gemini 及 Python 更新 Android 多语言 Excel 文件
android·python
纽马约1 小时前
Android RxJava的使用
android
励志不掉头发的内向程序员2 小时前
STL库——string(类模拟实现)
开发语言·c++
王廷胡_白嫖帝2 小时前
Qt文件压缩工具项目开发教程
java·开发语言·qt
张飞洪2 小时前
C# 13 与 .NET 9 跨平台开发实战:基于.NET 9 与 EF Core 9 的现代网站与服务开发
开发语言·c#·.net