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 灵魂操作符

场景 :用户快速搜索 aababcabcd,你希望只保留最后一次请求。

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 响应式方案。

相关推荐
石榴树下的七彩鱼1 小时前
AI抠图效果实测:基于Python的3种背景移除模型对比
开发语言·人工智能·python·ai抠图·石榴智能·背景移除·rmbg
逻辑驱动的ken1 小时前
Java高频面试考点场景题30
java·开发语言·深度学习·面试·职场和发展
zlpzlpzyd1 小时前
slf4j中jcl-over-slf4j、jul-to-slf4j、log4j-over-slf4j、slf4j-api的区别是什么
java·开发语言·log4j
monkeyhlj1 小时前
Agent Skills简单理解
开发语言·c#
eric*16881 小时前
彻底解决 INSTALL_FAILED_TEST_ONLY 安装失败的问题
android·android studio·install_failed_·error code·ailed_test_only·test_only·install_failed
河北之花1 小时前
Python第一节
开发语言·python
宠..1 小时前
下拉列表框事件绑定
开发语言·qt·microsoft
Tairitsu_H1 小时前
C++:优先队列的模拟实现
开发语言·c++·stl·优先队列
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题 第48题】【JVM篇】第8题:JVM 里的有几种 ClassLoader?为什么会有多种?
java·开发语言·jvm·面试