Kotlin Flow 完全指南

Kotlin Flow 完全指南

一、Flow 到底是什么

一句话:Flow = Kotlin 的"异步数据流"

它是:协程版 RxJava

但:

  • 更轻量
  • 更简单
  • 更符合 Kotlin 风格

你可以把 Flow 理解成:"会持续发数据的管道"

比如:

  • 网络请求状态
  • 输入框搜索
  • 倒计时
  • WebSocket
  • 数据库变化
  • 页面状态更新

这些都不是:只返回一次 ,而是:持续产生数据

这就是:Flow 的核心


二、先用最容易理解的例子

普通函数

kotlin 复制代码
fun getData(): String {
    return "hello"
}

只能返回一次:hello → 结束

Flow

kotlin 复制代码
fun getFlow() = flow {
    emit("hello")
    delay(1000)
    emit("world")
}

它会:hello → 1秒后 → world

也就是:可以连续发送数据


三、最核心的两个东西

Flow 只有两个关键点:

方法 作用
emit() 发送数据
collect() 接收数据
kotlin 复制代码
flow.collect { }

四、第一个完整 Flow

创建

kotlin 复制代码
val flow = flow {
    emit(1)
    emit(2)
    emit(3)
}

收集

kotlin 复制代码
lifecycleScope.launch {
    flow.collect {
        println(it)
    }
}

输出:

复制代码
1
2
3

五、为什么必须在协程里 collect

因为:Flow 是挂起的

collect 本质是 suspend fun collect()

所以必须:launch 或在 suspend 函数里调用。


六、Flow 执行流程(超重要)

很多人学不会就是这里没懂。

Flow 是"冷流" ------ 你不 collect,它就不执行。

kotlin 复制代码
val flow = flow {
    println("开始")
    emit(1)
}

此时:什么都不会打印,因为没人收集。

collect 后:

kotlin 复制代码
flow.collect()

才会输出:开始 → 1


七、最经典 Android 场景

场景1:网络请求状态

这是实际项目最多的。

不使用 Flow

kotlin 复制代码
fun login(callback: Callback)

回调地狱。

Flow 版本

kotlin 复制代码
fun login() = flow {
    emit(Loading)
    val result = api.login()
    emit(Success(result))
}

页面:

kotlin 复制代码
lifecycleScope.launch {
    viewModel.login().collect {
        when(it) {
            is Loading -> showLoading()
            is Success -> showData()
        }
    }
}

这就是:MVVM + Flow,现代 Android 标配。


八、StateFlow(真正项目核心)

实际项目用最多的不是 Flow,而是:StateFlow

因为 UI 需要:

  • 始终持有最新状态

九、StateFlow 最容易理解方式

它像:LiveData 升级版

但:

  • 协程化
  • 更强
  • 更快
  • 支持 Flow 全家桶

十、最经典 StateFlow

ViewModel

kotlin 复制代码
class MainViewModel : ViewModel() {

    private val _state = MutableStateFlow("默认值")
    val state = _state.asStateFlow()

    fun update() {
        _state.value = "新数据"
    }
}

页面监听

kotlin 复制代码
lifecycleScope.launch {
    viewModel.state.collect {
        tv.text = it
    }
}

StateFlow 最大特点:永远有值

kotlin 复制代码
MutableStateFlow("默认值")

必须给初始值,因为它代表:当前状态


十一、为什么 Google 推荐 StateFlow 替代 LiveData

特性 StateFlow LiveData
协程支持 强 弱
操作符 超多 很少
Kotlin 化 完全 一般
冷热流支持 支持 不支持
性能 更强 一般
官方趋势 主推 逐渐弱化

十二、实际项目最常见结构:UIState

现代 Android 必会。

定义状态

kotlin 复制代码
sealed class UIState {
    object Loading : UIState()
    data class Success(val data: String) : UIState()
    data class Error(val msg: String) : UIState()
}

ViewModel

kotlin 复制代码
private val _uiState = MutableStateFlow<UIState>(UIState.Loading)
val uiState = _uiState.asStateFlow()

// 更新状态
viewModelScope.launch {
    try {
        val result = api.getData()
        _uiState.value = UIState.Success(result)
    } catch (e: Exception) {
        _uiState.value = UIState.Error("失败")
    }
}

页面

kotlin 复制代码
lifecycleScope.launch {
    viewModel.uiState.collect {
        when(it) {
            is UIState.Loading -> { /* show loading */ }
            is UIState.Success -> { /* show data */ }
            is UIState.Error -> { /* show error */ }
        }
    }
}

十三、SharedFlow 是什么

一句话:可广播事件流

  • StateFlow:保存状态
  • SharedFlow:发送事件

十四、最经典场景:Toast

Toast:一次性事件,不应该保存状态。

SharedFlow

kotlin 复制代码
private val _event = MutableSharedFlow<String>()
val event = _event

// 发送
_event.emit("登录成功")

// 页面
collect {
    Toast.makeText(context, it, Toast.LENGTH_SHORT).show()
}

十五、为什么 Toast 不能用 StateFlow

因为 StateFlow 会记住最后一个值。

旋转屏幕后:Toast 又弹一次

这就是经典的 LiveData Event 问题,SharedFlow 可以避免。


十六、Flow 最重要操作符

map --- 数据转换

kotlin 复制代码
flow.map { it * 2 }

filter --- 过滤

kotlin 复制代码
flow.filter { it > 10 }

debounce(Android 超常用)--- 防抖

搜索框神器:

kotlin 复制代码
editTextFlow.debounce(500)
// 停止输入500ms后才搜索

十七、搜索框实战(面试高频)

kotlin 复制代码
editTextFlow
    .debounce(500)
    .distinctUntilChanged()
    .collect { search(it) }
操作符 含义
debounce 停止输入再搜索,避免疯狂请求
distinctUntilChanged 内容没变不重复搜索

十八、flatMapLatest(巨重要)

这是:Flow 灵魂操作符

场景 :用户快速搜索 a → ab → abc → abcd,你希望只保留最后一次请求。

kotlin 复制代码
queryFlow.flatMapLatest { repository.search(it) }

效果:

  • 旧请求:自动取消
  • 只保留:最新请求

十九、Android 搜索框完整实战

kotlin 复制代码
searchFlow
    .debounce(300)
    .distinctUntilChanged()
    .flatMapLatest { repository.search(it) }
    .flowOn(Dispatchers.IO)
    .collect { adapter.submitList(it) }

二十、flowOn 是什么

切线程:

kotlin 复制代码
flow {
    emit(api.getData())
}.flowOn(Dispatchers.IO)

表示:上游在 IO 线程

collect 默认在当前协程线程,通常是 Main。


二十一、catch 异常处理

kotlin 复制代码
flow {
    emit(api.getData())
}.catch {
    emit(emptyList())
}

二十二、onStart --- 开始加载

kotlin 复制代码
flow.onStart { showLoading() }

二十三、onCompletion --- 结束

kotlin 复制代码
flow.onCompletion { hideLoading() }

二十四、Room 为什么天然支持 Flow

kotlin 复制代码
@Query("SELECT * FROM users")
fun getUsers(): Flow<List<User>>

数据库变化:自动通知 UI

这是:响应式数据库


二十五、Compose 为什么和 Flow 天生搭配

  • Compose:状态驱动 UI
  • Flow:状态流

天然适配:

kotlin 复制代码
val state by viewModel.state.collectAsState()

UI 自动刷新。


二十六、Flow vs LiveData

对比 Flow LiveData
协程支持 强 弱
操作符 超多 很少
Kotlin 化 完全 一般
冷热流支持 支持 不支持
性能 更强 一般
官方趋势 主推 逐渐弱化

二十七、Flow vs RxJava

对比 Flow RxJava
学习成本 低 高
Kotlin 支持 官方 一般
操作符数量 中等 超多
Android 官方 主推 非主推
协程融合 原生 不自然

二十八、项目里真正怎么用

现代 Android 通常:

  1. Repository 返回 Flow:fun getData(): Flow<Data>
  2. ViewModel 转 StateFlow:MutableStateFlow
  3. UI collect
  4. repeatOnLifecycle

二十九、repeatOnLifecycle(非常重要)

错误写法:

kotlin 复制代码
launch {
    flow.collect {}
}

页面退出可能还在收集。

正确写法:

kotlin 复制代码
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        flow.collect { }
    }
}
  • 页面不可见:自动停止
  • 页面回来:自动恢复

三十、Android 项目最佳实践结构

Repository

kotlin 复制代码
fun getUser() = flow {
    emit(api.getUser())
}

ViewModel

kotlin 复制代码
val uiState = repository.getUser()
    .stateIn(
        viewModelScope,
        SharingStarted.WhileSubscribed(),
        UIState.Loading
    )

Activity/Fragment

kotlin 复制代码
repeatOnLifecycle(Lifecycle.State.STARTED) {
    viewModel.uiState.collect { }
}

三十一、最容易记忆的一张图

复制代码
Flow
├── 数据流
├── emit → 发数据
└── collect → 收数据

StateFlow → 保存状态
SharedFlow → 发送事件
flatMapLatest → 只保留最新请求
debounce → 防抖
flowOn → 切线程

三十二、面试高频回答模板

如果面试问:Flow 有什么用?

可以这样答:

Flow 是 Kotlin 协程提供的异步数据流,用于替代传统 Callback、LiveData、部分 RxJava。

Flow 支持:持续数据发送、协程挂起、操作符链式调用、线程切换、异常处理。

Android 项目中:通常 Repository 返回 Flow,ViewModel 使用 StateFlow 管理 UI 状态,SharedFlow 处理一次性事件。

常见场景:网络请求、搜索防抖、Room 数据监听、Compose 状态更新、WebSocket、分页加载。

Google 官方目前推荐:Flow + StateFlow 作为现代 Android 响应式方案。

相关推荐
Ada's38 分钟前
【计算机基础系列】003:Python数据结构
开发语言·数据结构·python
2601_962885721 小时前
如何用 Python 计算 TRIX 三重指数平滑均线指标?
开发语言·python
还卿一钵无情泪2 小时前
Unsloth 微调 构建自己的大模型 没有GPU也能微调
linux·开发语言·人工智能·python·大模型·nlp·unsloth
alexhilton3 小时前
模块化Jetpack Compose架构
android·kotlin·android jetpack
倔强的石头1063 小时前
应用账号最小权限实践:读写账号、报表账号、运维账号分层
java·运维·开发语言
传人once3 小时前
页面中心圆圈放大效果如何写
开发语言·javascript·ecmascript
NeilYuen3 小时前
【C++】STL源码仿写(二):vector
开发语言·c++
蜗牛互联网4 小时前
Python消费Responses SSE事件:增量文本、超时与取消
java·开发语言·人工智能·后端·python
weixin_307779134 小时前
C++代码实现MATLAB中的crossval函数功能
开发语言·c++·算法·matlab
ttwuai5 小时前
Go后台管理系统开源项目:4个官方仓库怎么追溯和核验
开发语言·golang·开源