Kotlin Flow常用封装类StateFlow使用详解

目录
  • Kotlin中StateFlow的使用
    • 一、StateFlow的使用
    • 二、替代LiveData
  • 总结

Kotlin中StateFlow的使用

StateFlow 是 Flow 的实现,是一个特殊的流,默认的 Flow 是冷流,而StateFlow 是热流,和 LiveData 比较类似。关于冷热流后面一期 SharedFlow 会详细说明。

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

StateFlow的特点

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

官方推荐当暴露 UI 的状态给视图时,应该使用 StateFlow。这是一种安全和高效的观察者,专门用于容纳 UI 状态。

一、StateFlow的使用

方式一,我们自己 new 出来

一般我们再ViewModel中定义读写分类的StateFlow

@HiltViewModel
class Demo4ViewModel @Inject constructor(
    val savedState: SavedStateHandle
) : BaseViewModel() {
    private val _searchFlow = MutableStateFlow("")
    val searchFlow: StateFlow<String> = _searchFlow
    fun changeSearch(keyword: String) {
        _searchFlow.value = keyword
    }
}

在Activity中我们就可以像类似 LiveData 一样的使用 StateFlow

    private fun testflow() {
       mViewModel.changeSearch("key")
    }
    override fun startObserve() {
        lifecycleScope.launchWhenCreated {
            mViewModel.searchFlow.collect {
                YYLogUtils.w("value $it")
            }
        }
    }

方式二,通过一个 冷流 Flow 转换为 StateFlow

    val stateFlow = flowOf(1, 2, 3).stateIn(
            scope = lifecycleScope,
//            started = WhileSubscribed(5000, 1000),
//            started = Eagerly,
            started = Lazily,
            initialValue = 1
        )
        lifecycleScope.launch {
            stateFlow.collect {
            }
        }

几个重要参数的说明如下

  • scope 共享开始时所在的协程作用域范围
  • started 控制共享的开始和结束的策略
  • Lazily: 当首个订阅者出现时开始,在 scope 指定的作用域被结束时终止。
  • Eagerly: 立即开始,而在 scope 指定的作用域被结束时终止。
  • WhileSubscribed能够指定当前不有订阅者后,多少时间取消上游数据和能够指定多少时间后,缓存中的数据被丢失,回复称initialValue的值。
  • initialValue 初始值

二、替代LiveData

不管是普通的 ViewModel 观察订阅模式,在Activity中订阅,还是DataBinding的模式,我们都可以使用StateFlow来代替ViewModel

    val withdrawMethod = MutableStateFlow(0)
    <ImageView
        android:id="@+id/iv_giro_checked"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="@dimen/d_15dp"
        android:src="@drawable/pay_method_checked"
        android:visibility="gone"
        binding:isVisibleGone="@{viewModel.withdrawMethod == 1}" />

为什么我们需要用StateFlow来代替LiveData,或者说LiveData有什么缺点?

LiveData vs Flow

先上代码,看看它们的用法与差异

ViewModel的代码

@HiltViewModel
class Demo4ViewModel @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中触发与接收事件

    private fun testflow() {
       mViewModel.changeSearch("key")
    }
    override fun startObserve() {
        mViewModel.searchLD.observe(this){
            YYLogUtils.w("value $it")
        }
        lifecycleScope.launchWhenCreated {
            mViewModel.searchFlow.collect {
                YYLogUtils.w("value $it")
            }
        }
    }

可以看到基本的使用几乎是没有差异,在DataBinding中同样的是都能使用。那么它们有哪些差异呢?

它们相同的地方:

  • 仅持有单个且最新的数据
  • 自动取消订阅
  • 提供「可读可写」和「仅可读」两个版本收缩权限
  • 配合 DataBinding 实现「双向绑定」

相比StateFlow ,LiveData的确定:

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

这么惨,那我们开发是不是要放弃LiveData了?

恰恰不是!

如果大家全部是Koltin代码开发,那么是可以用Flow,这是基于Kotlin代码,基于协程实现的,但是现在很多项目还是 Java 语言开发的。那么LiveData还是很香的。

其二是LiveData的学习成本与 协程、Flow 的学习成本不可同日而语,开发项目是整个团队的事情,不能说你一个人会一个人用,目前LiveData的简单学习成本是很有优势的。

只是我们需要在一些特定的场景慎重使用postValue,比如数据比较秘籍的场景,我们尽量使用setValue方法。

总结

如果大家的项目的语言是 Kotlin ,并且小组成员都会 Flow 。那么我推荐你们使用StateFlow 替代LiveData 。如果不是,那么 LiveData 是你最好的选择。

谷歌也只是推荐使用Flow替代LiveData。但是并没有说打算放弃 LiveData 。并且 LiveData 与 StateFlow 都有各自的使用场景,不需要担心 LiveData的 使用。

本文我们只是简单的对比,关于StateFlow 与 SharedFlow 和LiveData 三者的差异与选择,后面等SharedFlow那一期详细的讲解。

为什么很多东西都要等SharedFlow,是因为 SharedFlow 是 StateFlow 的基础,StateFlow 像是 SharedFlow 的‘青春版’。很多东西需要讲完 SharedFlow 才能把知识点串起来,更多关于Kotlin Flow封装类StateFlow的资料请关注我们其它相关文章!

(0)

相关推荐

  • 图解 Kotlin SharedFlow 缓存系统及示例详解

    目录 前言 replay extraBufferCapacity onBufferOverflow SharedFlow Buffer 前言 Kotlin 为我们提供了两种创建“热流”的工具:StateFlow 和 SharedFlow.StateFlow 经常被用来替代 LiveData 充当架构组件使用,所以大家相对熟悉.其实 StateFlow 只是 SharedFlow 的一种特化形式,SharedFlow 的功能更强大.使用场景更多,这得益于其自带的缓存系统,本文用图解的方式,带大家更

  • Kotlin协程之Flow基础原理示例解析

    目录 引言 一.Flow的创建 二.Flow的消费 1.SafeFlow类 2.AbstractFlow类 3. SafeCollector类 4.消费过程中的挂起 引言 本文分析示例代码如下: launch(Dispatchers.Main) { flow { emit(1) emit(2) }.collect { delay(1000) withContext(Dispatchers.IO) { Log.d("liduo", "$it") } Log.d(&qu

  • Kotlin Flow常见场景下的使用实例

    目录 Kotlin Flow在开发中的常用场景使用 一.网络请求搭载Retrofit 1.1 LiveDataCallAdapterFactory 1.2 suspend 二.协程与Flow的选择与差异 三.StateFlow与SharedFlow的选择 总结 Kotlin Flow在开发中的常用场景使用 大家了解了 Flow 的创建与接收流程,了解 SharedFlow 创建的几种方式,各个参数的用途,了解了SharedFlow的 "青春版" StateFlow 的创建与接收,已经他

  • Kotlin协程Flow生命周期及异常处理浅析

    目录 正文 Flow基本概念 Flow生命周期 处理异常 上游或者中间异常使用catch 下游使用try-catch 切换执行线程 终止操作符 "冷的数据流"从何而来 正文 Kotlin协程中的Flow主要用于处理复杂的异步数据,以一种”流“的方式,从上到下依次处理,和RxJava的处理方式类型,但是比后者更加强大. Flow基本概念 Flow中基本上有三个概念,即 发送方,处理中间层,接收方,可以类比水利发电站中的上游,发电站,下游的概念, 数据从上游开始发送”流淌“至中间站被”处理

  • Kotlin Flow操作符及基本使用详解

    目录 一.Flow的基本概念 二.Flow的生命周期与异常处理 2.1 开始与结束 2.2 异常的处理 2.3 retry的处理 2.4 超时的处理 2.5 Flow的取消 三.Flow的创建方式 四.Flow的接收方式 五.Flow的转换操作符 5.1 基本操作符 5.2 特殊操作符 5.3 组合与展平操作符 5.4 切换线程 总结 一.Flow的基本概念 Kotlin 的 Flow 相信大家都或多或少使用过,毕竟目前比较火,目前我把Flow的使用整理了一下.希望和大家所学对照一下,能有所启发

  • Kotlin Flow封装类SharedFlow StateFlow LiveData使用对比

    目录 Kotlin中SharedFlow的使用 VS StateFlow SharedFlow的特点 一.SharedFlow的使用 二.SharedFlow.StateFlow.LiveData的对比 三.SharedFlow 的粘性设置与事件总线 总结 Kotlin中SharedFlow的使用 VS StateFlow SharedFlow 是继承于 Flow ,同时它是 StateFlow 的父类,它们都是是热流,先说一下冷流与热流的概念. 冷流 :只有订阅者订阅时,才开始执行发射数据流的

  • Android开发之Kotlin委托的原理与使用详解

    目录 前言 一.接口/类委托 二.属性委托 三.延迟委托 四.观察者委托 五.Map委托 总结 前言 在设计模式中,委托模式(Delegate Pattern)与代理模式都是我们常用的设计模式(Proxy Pattern),两者非常的相似,又有细小的区分. 委托模式中,委托对象和被委托对象都是同一类型的对象,委托对象将任务委托给被委托对象来完成.委托模式可以用于实现事件监听器.回调函数等功能. 代理模式中,代理对象与被代理对象是两种不同的对象,代理对象代表被代理对象的功能,代理对象可以控制客户对

  • Kotlin协程Dispatchers原理示例详解

    目录 前置知识 demo startCoroutineCancellable intercepted()函数 DefaultScheduler中找dispatch函数 Runnable传入 Worker线程执行逻辑 小结 前置知识 Kotlin协程不是什么空中阁楼,Kotlin源代码会被编译成class字节码文件,最终会运行到虚拟机中.所以从本质上讲,Kotlin和Java是类似的,都是可以编译产生class的语言,但最终还是会受到虚拟机的限制,它们的代码最终会在虚拟机上的某个线程上被执行. 之

  • Kotlin语言编程Regex正则表达式实例详解

    目录 前言 Regex 构造函数 常用正则表达方法 示例展示 1.containsMatchIn(input: CharSequence) 包含指定字符串 2.matches(input: CharSequence) 匹配字符串 3.find(input: CharSequence, startIndex: Int = 0) 查找字符串,并返回第一次出现 4.findAll(input: CharSequence, startIndex: Int = 0) 查找字符串,返回所有出现的次数 5.r

  • 基于C++ bitset常用函数及运算符(详解)

    C++ bitset--高端压位卡常题必备STL ------------------------------------------------------------ 以下内容翻译自cplusplus.com,极大地锻炼了我的英语能力. bitset存储二进制数位. bitset就像一个bool类型的数组一样,但是有空间优化--bitset中的一个元素一般只占1 bit,相当于一个char元素所占空间的八分之一. bitset中的每个元素都能单独被访问,例如对于一个叫做foo的bitset,

  • mysql常用日期时间/数值函数详解(必看)

    1.日期时间函数 时间转化秒函数:time_to_sec MySQL> select time_to_sec('01:01:01'); +-------------------------+ | time_to_sec('01:01:01') | +-------------------------+ | 3661 | +-------------------------+ 1 row in set (0.00 sec) 秒转化时间函数:sec_to_time mysql> select se

  • Kotlin + Retrofit + RxJava简单封装使用详解

    本文介绍了Kotlin + Retrofit + RxJava简单封装使用详解,分享给大家,具体如下: 实例化Retrofit object RetrofitUtil { val CONNECT_TIME_OUT = 30//连接超时时长x秒 val READ_TIME_OUT = 30//读数据超时时长x秒 val WRITE_TIME_OUT = 30//写数据接超时时长x秒 val retrofit: Retrofit by lazy { Log.d("RetrofitUtil"

  • Ubuntu常用指令及用法详解

    1.ls 这个相当于Windows 下的dir命令,可以列出当前窗口或指定窗口下的内容. 2.rm 这个相当于Windows 下的del 和rmdir 命令,可以删除文件及文件夹. 常见用法:rm -rf/home/ubuntu/.cache (删除 /home/ubuntu/.cache这个文件夹) 禁忌:rm-rf /* 这个命令会删除根分区下所有文件,在某些efi机器上还会删除主板固件,造成主板固件丢失从而无法开机(比操作系统无法启动还严重). 3.chmod 更改文件权限,类似于Wind

  • C#Button窗体常用属性及事件详解

    1.常用属性 Name:名称: BackColor:设置控件背景颜色: Enabled:是否可用: FlayStyle:控件样式: Image:设置控件图像: ImageAlign:图像对齐方式: ImageList:图像ImageList索引值: Location:坐标: Size:大小: Tabindex:控件顺序索引: Text:文本: TextAlign:文本对齐方式: Visible:控件是否可见: 2.控件事件: Click:单击事件: 知识点扩充: 在真实的C#开发场景中,我们对于

随机推荐