当前位置:网站首页>Kotlin-Flow常用封装类:StateFlow的使用
Kotlin-Flow常用封装类:StateFlow的使用
2022-08-03 04:27:00 【代码与思维】
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 才能把知识点串起来,期待一下。
作者:newki
链接:https://juejin.cn/post/7127082531358244900
来源:稀土掘金
边栏推荐
- 4.深度学习的几何解释与梯度的优化
- 6.神经网络剖析
- The flink sql task is changed, and after adding several fields to the sql, an error occurs when restoring from the previously saved savepoint.
- 汇编题答案
- 数字化时代,企业如何建立自身的云平台与商业模式的选择?
- 软件开发的最大的区别是什么?
- UV 裂解的生物素-PEG2-叠氮|CAS:1192802-98-4生物素接头
- 汇编书摘抄
- 打破传统电商格局,新型社交电商到底有什么优点?
- 【Harmony OS】【FAQ】鸿蒙问题合集1
猜你喜欢
随机推荐
汇编题答案
计组错题集
探索性测试的概念及方法
私域流量引流方法?分享购火爆的商业模式,你值得拥有
js的垃圾回收机制
2022河南萌新联赛第(四)场:郑州轻工业大学 G - 迷宫
肖sir__简历
DC-5靶场下载及渗透实战详细过程(DC靶场系列)
常见亲脂性细胞膜染料DiO, Dil, DiR, Did光谱图和实验操作流程
基于Streamlit的YOLOv5ToX模型转换工具(适用YOLOv5训练出来的模型转化为任何格式)
MediaRecorder录制屏幕时在部分机型上报错prepare failed:-22
如何利用 Flutter 实现炫酷的 3D 卡片和帅气的 360° 展示效果
Shell条件语句判断
肖sir_测试点
OpenFOAM提取等职面并计算面积
lc marathon 8.2
肖sir___面试就业课程____app
TCP相关面试常问
DC-3靶场搭建及渗透实战详细过程(DC靶场系列)
MySQL 出现 The table is full 的解决方法