协程学习记录之提问Kimi:介绍一下Flow的用法

Kotlin Flow 是 Kotlin 协程生态中专门处理异步、连续数据流 的 API,官方推荐的响应式编程利器。下面按照"创建 → 加工 → 收集 → 线程切换 → 生命周期管理"的顺序,一次性讲透 Flow 的核心用法与最佳实践。


1. 创建 Flow(生产者)

方式 场景示例
flow { ... } 通用构造器 手动 emit 发射任意值,可调用挂起函数
flowOf(...) 快速把固定元素转成 Flow
.asFlow() 把集合、序列、Range 直接变 Flow
kotlin 复制代码
val tickerFlow = flow {
    while (true) {
        emit(api.fetchNews())   // 网络请求
        delay(5000)             // 每 5 秒拉一次
    }
}

2. 加工 Flow(中间操作符)

所有中间操作都是 冷流、惰性执行,直到被末端操作符触发。

常用链式操作:

kotlin 复制代码
flow
    .filter { it.isNotEmpty() }   // 过滤
    .map { it.toUiModel() }       // 转换
    .distinctUntilChanged()       // 去重
    .onEach { cache(it) }         // 副作用

3. 收集 Flow(末端操作符)

操作符 作用
collect 最通用,挂起函数,需协程作用域
collectLatest 新值到达时取消旧收集,适合搜索框防抖
toList() / first() / single() 终端快捷函数
kotlin 复制代码
lifecycleScope.launchWhenStarted {
    vm.newsFlow.collect { list ->
        adapter.submitList(list)
    }
}

4. 线程切换

使用 flowOn 仅改变上游执行线程,下游仍在原作用域线程。

kotlin 复制代码
flow
    .map { heavyCpu(it) }          // 默认线程
    .flowOn(Dispatchers.Default)   // 改到 Default
    .collect { updateUI(it) }      // 回到主线程

5. Android 生命周期级 Flow

作用域 说明
viewModelScope ViewModel 销毁时自动取消
lifecycleScope Activity/Fragment 生命周期作用域
repeatOnLifecycle 生命周期安全收集(官方推荐)
kotlin 复制代码
// 在 Fragment 中
viewLifecycleOwner.lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        vm.uiState.collect { render(it) }
    }
}

6. StateFlow & SharedFlow(UI 状态专用)

类型 特点 典型用法
StateFlow<T> 有初始值、粘性、只保留最新值 UI 单向状态
SharedFlow<T> 无初始值、可配置重播、支持多订阅 事件总线

ViewModel → UI 的最简模板:

kotlin 复制代码
class VM : ViewModel() {
    private val _state = MutableStateFlow(Loading)
    val state = _state.asStateFlow()

    fun load() = viewModelScope.launch {
        _state.value = repo.load()
    }
}

在 Compose 中:

kotlin 复制代码
val state by vm.state.collectAsStateWithLifecycle()

7. 取消与背压

  • 协程作用域取消 → Flow 自动结束。
  • 使用 cancellable() 操作符显式支持取消检查。
  • buffer() / conflate() / collectLatest() 处理背压。

8. 完整示例:网络 → 缓存 → UI

kotlin 复制代码
class NewsRepo(
    private val api: NewsApi
) {
    fun news(): Flow<List<Article>> = flow {
        while (true) {
            emit(api.fetch())          // 网络
            delay(30_000)              // 30 秒轮询
        }
    }
    .flowOn(Dispatchers.IO)            // 网络线程
    .onEach { cache.save(it) }         // 缓存
    .catch { emit(cache.get()) }       // 失败兜底
}

9. 一站式学习资源


一句话总结:
Flow = 协程 + 响应式,把"一次性"的 suspend 函数升级为"持续不断"的异步数据流,Android 官方推荐的现代异步方案。

相关推荐
愚公搬代码20 分钟前
【愚公系列】《Web应用安全》001-VMware的安装
前端·安全
xiaohaiAIgeo21 分钟前
【2026年】HG/T 20656-2024化工暖通空调设计规范:新版标准的变化与影响
java·前端·javascript·科普知识
立少→万能汉编23 分钟前
用“立少→超文本”写静态网页,标签<倍>
服务器·前端·javascript
weixin_4316004432 分钟前
NestJS 入门(7):生命周期钩子——构造函数和 `OnModuleInit` 差在哪?
前端·后端·学习·node.js·nest.js
你挚爱的强哥1 小时前
【chromeDownload】自定义组件:多用于登录框底部提供下载Chrome谷歌浏览器的链接
前端·vue.js·chrome
cindershade1 小时前
用原生 HTML5 视频与 Canvas 实现浏览器端视频抽帧封面
前端
笨鸟先飞,勤能补拙1 小时前
Web 服务器与计算机网络全景原理
运维·服务器·前端·网络·人工智能·计算机网络·web安全
NutShell Wang2 小时前
Wails v3 Beta 实战:用显式对象模型重写你的第一个 Go 桌面应用
前端·人工智能·go·vibe coding
cindershade2 小时前
前端国际化工程实践:语言包拆分、动态加载与日期数字格式统一
前端
kisbad2 小时前
Day 036|OpenAI Agents SDK 快速开始:今天跑通第一个 Agent
java·前端·javascript