Android Flow的其他使用:stateIn和冷流(普通Flow)

一、数据库使用冷流(普通Flow)和热流(stateIn转换)的区别

scss 复制代码
val lightFlow = DataBase.getInstance()
    .getLightDao()
    .getData()
    .flowOn(Dispatchers.IO) // 在 IO 线程执行查询
ini 复制代码
val lightHistoryFlow = DataBase.getInstance().getLightDao().queryLimitCountF(50).map {
    if (it.isEmpty()) {
        LightData.fakeData(
            listOf(
                LightEntity(value =400f, time = Date()),
                 LightEntity(value =500f, time = Date()),
            )
        )
    } 
}.stateIn(
    scope = viewModelScope,
    started = SharingStarted.WhileSubscribed(5000),
    initialValue = LightData.fakeData(emptyList())
)

1.1 两段代码的核心区别

特性 lightFlow(普通 Flow) lightHistoryFlow(StateFlow)
流类型 冷流(Flow 热流(通过stateIn转换为StateFlow
状态持有 不持有状态,无初始值 持有状态,有initialValue
订阅行为 每次collect都会触发数据源重新执行(如数据库查询) 多次collect共享同一数据流,数据源只执行一次
新订阅者 重新执行上游逻辑(重新查数据库) 立即收到当前持有的状态值,不会重新执行上游
生命周期 与订阅者绑定,无订阅时上游逻辑停止 与指定的scope绑定,在started条件满足时保持活跃

lightFlow(普通冷流)

  • 每次调用collect时,都会重新执行getData()对应的数据库查询
  • 没有 "当前值" 的概念,订阅者只能获取订阅之后产生的新数据
  • 当所有订阅者取消订阅后,上游的数据库查询会停止(冷流特性)

执行流程:

复制代码
订阅1 → 触发数据库查询 → 发射结果
订阅2 → 再次触发数据库查询 → 发射结果
所有订阅取消 → 数据库查询停止

lightHistoryFlow(热流 StateFlow)

  • 通过stateIn将冷流转换为热流,数据库查询queryLimitCountF(50)只会执行一次
  • 结果会被缓存为 "状态",新订阅者立即收到当前缓存的状态(initialValue或最新结果)
  • viewModelScopeSharingStarted.WhileSubscribed(5000)控制生命周期:当有活跃订阅时保持数据更新,无订阅 5 秒后停止上游,节省资源

执行流程:

复制代码
首次订阅 → 触发数据库查询 → 结果缓存为状态 → 所有订阅者共享该状态
新订阅者加入 → 直接获取当前缓存状态(不查数据库)
无订阅5秒后 → 停止上游,但保留最后状态
再次订阅 → 立即返回保留的状态,同时重新启动上游更新

1.2具体建议

在你的健康数据场景中:

  • 如果lightFlow是 "获取最新光照
    建议改为StateFlow,避免重复查询数据库:
ini 复制代码
val LightFlow = DataBase.getInstance()
    .getLightDao()
    .getData()
    .flowOn(Dispatchers.IO) // 在 IO 线程执行查询
    .stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5000),
        initialValue = null // 适合的初始值
    )
  • lightHistoryFlow的写法是合理的
    历史记录数据适合作为 "状态" 缓存,且可能被多个 UI 组件订阅,stateIn能有效减少数据库查询次数,提升性能。
相关推荐
程序员卷卷狗8 小时前
MySQL 慢查询优化:从定位、分析到索引调优的完整流程
android·mysql·adb
写点啥呢9 小时前
Android Studio 多语言助手插件:让多语言管理变得简单高效
android·ai·ai编程·多语言
泥嚎泥嚎11 小时前
【Android】给App添加启动画面——SplashScreen
android·java
全栈派森11 小时前
初见 Dart:这门新语言如何让你的 App「动」起来?
android·flutter·ios
q***985211 小时前
图文详述:MySQL的下载、安装、配置、使用
android·mysql·adb
恋猫de小郭11 小时前
Dart 3.10 发布,快来看有什么更新吧
android·前端·flutter
恋猫de小郭13 小时前
Flutter 3.38 发布,快来看看有什么更新吧
android·前端·flutter
百锦再18 小时前
第11章 泛型、trait与生命周期
android·网络·人工智能·python·golang·rust·go
会跑的兔子19 小时前
Android 16 Kotlin协程 第二部分
android·windows·kotlin
键来大师19 小时前
Android15 RK3588 修改默认不锁屏不休眠
android·java·framework·rk3588