深入探讨kotlin StateFlow的两个问题和使用场景

 更新时间:2025年08月01日 09:21:46   作者:jzlhll123  
文章探讨Kotlin中LiveData与Flow的适用场景,指出LiveData适合一次性请求且避免重复触发,而StateFlow因热流特性易导致冗余更新,建议多数场景优先使用SharedFlow,因其无初始值、不自动去重,更灵活适配网络请求等需求,感兴趣的朋友一起看看吧

背景说明:
我们日常开发中,经常要在一个独立的界面上做网络请求显示或者toast报错,以及错误信息展示。
LiveData是粘性事件,如果有值(或者有初始值),再注册监听,就会立刻触发。然后就是网络请求,将结果设置到LiveData上,等待回调。
这个流程相信是99%的开发任务。其实使用Flow我认为是杀鸡用牛刀。LiveData我认为在这种场景下,是更好的选择。因为我们99%的场景并非“流”!都是一次请求,或者下拉刷新获取一次结果并展示,而且会屏蔽中间的快速刷新动作,避免过多请求。
好了,既然谈到Flow,自然要用它来替代LiveData。

开发实践模板规范

如下是参考开发规范做的:
首先定义一个状态包裹类,便于后续解析和分类:

sealed class StatusState<out T> {
    object Loading : StatusState<Nothing>()
    //官方就是data class。注意有坑,后续介绍。我推荐移除data
    data class Success<out T>(val data: T) : StatusState<T>() 
    //官方就是data class。注意有坑,后续介绍。我推荐移除data
    data class Error(val message: String?) : StatusState<Nothing>()
}

第2步,在ViewModel申明;然后调用Api接口,赋值给value:

//申明为StateFlow
	private val _userInfo = MutableStateFlow<StatusState<Bean>>(StatusState.Loading)
	val userInfo: StateFlow<StatusState<Bean>> = _userInfo.asStateFlow()
	fun requestXXX(xxx) {
    	viewModelScope.launch {
	        try {
	        val data = Api.request(xx)
	        _userInfo.value = StatusState.Success(data)
	    } catch (e: Exception) {
	        _userInfo.value = StatusState.Error(e.message)
	    }
    }
}

第3步,在Fragment/Activity中collect,如下的 lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) {}}套路也是官方推荐的:

onCreate() {
       lifecycleScope.launch {
         repeatOnLifecycle(Lifecycle.State.STARTED) {
             viewModel.userInfo.collect{
                 //解析为正确
				//...ShowDialog()
				// 解析为error
				//...toast(exMsg)
             }
         }
        }
 	}

坑来了

1. 每次onStart就触发一次

比如跳转到下一页返回,或者Home键再返回。立刻就触发。像我这里一回来toast一下,不太合适吧?
为什么会这样:

  • 理解collect{}函数:
    • 研究了函数代码,可以理解为一个死循环,等待协程唤醒(谁?当然是我们flow发生数据变化);唤醒一次执行一次你的collect的代码。然后,进入下一次等待。
  • 理解repeatOnLifecycle(Lifecycle.State.STARTED):
    • 当生命周期离开STARTED即onStop的时候,把collect这个执行死循环给cancel掉了。然后,当STARTED即onStart的时候,立刻触发collect{}动作,死循环又回来了。

这就是repeatOnLifecycle(Life...START) + flow collect的原理。

  • 再看StateFlow的总结特性,“热流”属性,始终持有最新状态值(通过 value 属性)。
  • 新订阅者立即获取最新值:当收集重新启动时(进入 STARTED),StateFlow 会立即将当前最新值(value)发送给收集器,即使该值之前已发送过。

这就导致了它的触发。但往往我们不需要这种特性。

2. 数据相同不触发

总结图中有说了,自动去重,连续相同值不会触发更新。虽然你的网络请求已经执行,用户手都点麻了,但是就是不触发collect。按道理来讲,相同的网络结果,也就你点了几次,就弹几次,不然疯狂刷新没个反馈,不好吧?

而且明明我每次都是新建的对象呀,为什么也不更新?

//网络请求结果设置
	_userInfo.value = StatusState.Error(it.msg)

这又是另外一个坑,原因在于,data class会自行实现equals各个字段比较,相同就不触发collect。因此当我改成不使用data class,那么他每次比较的是2个对象的地址,自然是不一样的。这与LiveData 或者 SharedFlow是有区别的,liveData允许使用重复的对象。

怎么解决

使用SharedFlow。

首先它没有初始值。并且,它不会相同对象或者equals相同就不更新,就可以使用data class。
而且每次重新collect的时候,并无缓存(你不修改MutableSharedFlow申明参数),也就不会触发。
我想SharedFlow才是替代LiveData的真正最佳对象。

总结

回归我前面说的,我们真的需要使用StateFlow吗?
我想我们在99%普通页面上的需求的时候,应该优先需要的是SharedFlow。

到此这篇关于kotlin StateFlow的两个问题和使用场景探讨的文章就介绍到这了,更多相关kotlin StateFlow使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Android Dialog仿ios9中UIAlertController控件

    Android Dialog仿ios9中UIAlertController控件

    这篇文章主要为大家详细介绍了Android Dialog仿ios9中UIAlertController控件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-06-06
  • 基于Android应用中如何反馈Crash报告的详解

    基于Android应用中如何反馈Crash报告的详解

    本篇文章是对在Android应用中如何反馈Crash报告的详细分析介绍。需要的朋友参考下
    2013-05-05
  • Android Studio的中文乱码问题解决方法

    Android Studio的中文乱码问题解决方法

    Android Studio安装后发现所有的中文,不管是界面上的还是输出的log中的中文都变成小框框,具体的解决方法如下,感兴趣的朋友可以参考下哈
    2013-06-06
  • Android Studio中的Gradle依赖深入讲解

    Android Studio中的Gradle依赖深入讲解

    Android Studio由于使用了gradle的进行项目构建,使我们开发app方便很多,下面这篇文章主要给大家介绍了关于Android Studio中Gradle依赖的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2018-09-09
  • Android串口操作方法实例

    Android串口操作方法实例

    这篇文章主要介绍了Android串口操作方法实例,本文共分5个步骤讲解了Android串口操作方法,并给出代码实例,需要的朋友可以参考下
    2015-04-04
  • Android拍照上传功能示例代码

    Android拍照上传功能示例代码

    这篇文章主要介绍了Android拍照上传功能用法,结合实例形式详细分析了Android拍照上传功能所涉及的相关知识点与功能实现技巧,需要的朋友可以参考下
    2016-08-08
  • Android自定义view实现拖拽选择按钮

    Android自定义view实现拖拽选择按钮

    这篇文章主要为大家详细介绍了Android自定义view实现拖拽选择按钮,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • Android SharedPreferences存储用法详解

    Android SharedPreferences存储用法详解

    这篇文章主要为大家详细介绍了Android SharedPreferences存储用法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-02-02
  • Android编写2048小游戏

    Android编写2048小游戏

    这篇文章主要为大家详细介绍了利用Android编写一个2048小游戏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • 详解Android开发中Activity的四种launchMode

    详解Android开发中Activity的四种launchMode

    这篇文章主要介绍了Android开发中Activity的四种launchMode,launchMode主要用于控制多个Activity间的跳转,需要的朋友可以参考下
    2016-03-03

最新评论