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能有效减少数据库查询次数,提升性能。
相关推荐
HLC++5 小时前
Linux的进程间通信
android·linux·服务器
爱笑鱼8 小时前
Binder(二):AIDL 生成的 Proxy、Stub 和 Parcel 到底在做什么?
android
爱笑鱼9 小时前
Binder(一):一次方法调用,究竟怎样跨进程执行?
android
btown10 小时前
Kotlin 版 MyBatis-Plus 查询优雅解决方案
kotlin
壮哥_icon10 小时前
【Android 系统开发】使用 BAT 脚本高效自动化管理 /system/priv-app/ 系统应用(安装与卸载)
android·运维·自动化
用户693717500138411 小时前
Claude Code终端日志Token占用实测:一个过滤器砍掉60%-90%
android·前端·后端
蝉蜕日记11 小时前
AccumuPDF高级版 v2.57 | 视图文转换PDF,合并分割压缩
android·智能手机·pdf·生活·软件需求
吐了啊取名字太难11 小时前
美颜系统AI修图本地跑并支持Mac、win、安卓、iOS不卡顿
android·人工智能·windows·数码相机·mac·ai编程
小二·12 小时前
车载数字座舱实战:用魔珐星云打造下一代智能驾乘助手(附 Android/Kotlin 完整代码)
开发语言·kotlin
阿pin13 小时前
Android随笔-Retrofit
android·retrofit