Kotlin 协程 Flow 模块
1. 协程基础:挂起函数 suspend
suspend 关键字
// suspend 函数:可在特定点挂起协程,不会阻塞线程
suspend fun fetchUser(id: String): User {
// 网络请求会挂起,不会阻塞主线程
return api.getUser(id)
}
// 普通函数不能调用 suspend 函数
fun normalFunction() {
// fetchUser("1") // ❌ 编译错误
// 必须通过协程或 suspend 函数调用
}
// suspend 函数可调用 suspend 函数
suspend fun loadData(): List<User> {
val user = fetchUser("1") // ✅ OK
val posts = fetchPosts(user.id)
return combine(user, posts)
}
挂起原理
// Kotlin 协程编译器将 suspend 编译为状态机
// 挂起点:调用其他 suspend 函数、delay、await 等
// 伪代码展示挂起原理(实际编译器生成)
class loadDataCoroutine {
var label = 0
var result = emptyList<User>()
fun resume() {
when (label) {
0 -> {
label = 1
fetchUser("1").let { user ->
this.user = user
resume() // 回调继续
}
}
1 -> {
label = 2
// ...
}
}
}
}
launch / async 启动协程
import kotlinx.coroutines.*
// launch:启动不返回结果(fire-and-forget)
fun main() = runBlocking {
launch {
delay(1000)
println("Done 1")
}
launch {
delay(500)
println("Done 2")
}
println("Started")
// 输出:Started, Done 2, Done 1(500ms, 1000ms)
}
// async:启动并返回结果(用于并发)
suspend fun demo() = runBlocking {
val deferred = async {
delay(1000)
42
}
println("Waiting...")
val result = deferred.await() // 等待并获取结果
println("Result: $result") // Result: 42
}
// 并发执行
suspend fun parallelLoad() = runBlocking {
val start = System.currentTimeMillis()
val one = async { fetchOne() }
val two = async { fetchTwo() }
val three = async { fetchThree() }
val result = one.await() + two.await() + three.await()
// 三个请求并发执行,总耗时 ≈ 最慢的一个
println("Result: $result, took: ${System.currentTimeMillis() - start}ms")
}
2. 调度器 Dispatchers
三大调度器
import kotlinx.coroutines.Dispatchers
// Dispatchers.Main:主线程(UI 线程)
// Android:更新 UI
// Compose:Compose 线程
// 使用场景:UI 更新、LiveData.setValue、Compose state 更新
launch(Dispatchers.Main) {
textView.text = "Updated" // ✅ 主线程操作 UI
}
// Dispatchers.IO:I/O 操作(网络、磁盘、数据库)
// 适合:文件读写、网络请求、数据库操作
launch(Dispatchers.IO) {
val data = withContext(Dispatchers.IO) {
file.readText() // ✅ I/O 线程
}
// 自动切换回 Main 继续
withContext(Dispatchers.Main) {
textView.text = data // ✅ UI 更新
}
}
// Dispatchers.Default:CPU 密集型操作
// 适合:排序、JSON 解析、复杂计算
launch(Dispatchers.Default) {
val sorted = withContext(Dispatchers.Default) {
bigList.sorted() // ✅ CPU 密集型
}
}
调度器选择指南
| 调度器 |
线程池 |
使用场景 |
阻塞处理 |
Dispatchers.Main |
主线程 |
UI 更新、Compose、LiveData |
不阻塞 |
Dispatchers.IO |
弹性线程池(最多 64) |
网络、文件、数据库 I/O |
可阻塞 |
Dispatchers.Default |
CPU 核心数线程池(至少 2) |
CPU 密集计算 |
可阻塞 |
withContext 切换上下文
// withContext:切换到指定调度器,执行完自动切回
suspend fun loadImage(): Bitmap {
return withContext(Dispatchers.IO) {
Glide.with(context).asBitmap().load(url).submit().get()
}
}
// ViewModel 标准写法
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> = _data
fun load() {
viewModelScope.launch {
_data.value = "Loading..."
try {
val result = withContext(Dispatchers.IO) {
repository.fetchData()
}
_data.value = result
} catch (e: Exception) {
_data.value = "Error: ${e.message}"
}
}
}
}
// 连续切换
suspend fun process() {
withContext(Dispatchers.IO) { readFromDisk() }
.let { withContext(Dispatchers.Default) { parse(it) } }
.let { withContext(Dispatchers.Main) { updateUI(it) } }
}
调度器切换注意事项
// ❌ 错误:在 IO 操作后忘记切回 Main
launch(Dispatchers.IO) {
val data = api.getData()
// textView.text = data // ❌ 主线程更新,抛异常
}
// ✅ 正确:显式切换
launch(Dispatchers.IO) {
val data = api.getData()
launch(Dispatchers.Main) {
textView.text = data
}
}
// ✅ 正确:用 withContext
launch {
val data = withContext(Dispatchers.IO) { api.getData() }
textView.text = data // launch 已在 Main 启动
}
// ✅ 推荐:用 viewModelScope(自动在 Main 启动)
viewModelScope.launch {
val data = withContext(Dispatchers.IO) { api.getData() }
_data.value = data // Main 线程
}
3. 协程作用域 CoroutineScope
viewModelScope(ViewModel 官方推荐)
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
class MyViewModel : ViewModel() {
private val _items = MutableLiveData<List<Item>>()
val items: LiveData<List<Item>> = _items
fun loadItems() {
// viewModelScope 自动绑定 ViewModel 生命周期
viewModelScope.launch {
try {
_items.value = withContext(Dispatchers.IO) {
repository.getItems()
}
} catch (e: Exception) {
_items.value = emptyList()
}
}
}
// viewModelScope 会自动在 onCleared 时取消所有协程
}
// 生命周期绑定
// onCreate() -> 启动协程
// onCleared() -> 取消所有协程
// 配置变更(如旋转)-> viewModelScope 保持,自动取消旧协程
lifecycleScope(Activity/Fragment)
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.delay
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// lifecycleScope 绑定 Activity 生命周期
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
// 只在 STARTED 状态执行,STOPPED 时暂停,RESTARTED 时恢复
val data = repository.getData()
updateUI(data)
}
}
// launchWhenStarted:旧写法(不推荐,有泄漏风险)
lifecycleScope.launchWhenStarted {
// 只在 STARTED 时执行,STOPPED 时暂停
}
}
override fun onDestroy() {
super.onDestroy()
// lifecycleScope 自动取消,但 STOPPED 时已暂停
}
}
repeatOnLifecycle(官方推荐模式)
import androidx.lifecycle.repeatOnLifecycle
// repeatOnLifecycle:自动暂停/恢复
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
// STARTED 时开始执行
// STOPPED 时自动挂起(暂停)
// RESTARTED 时恢复执行
// DESTROYED 时取消(结束协程)
dataFlow.collect { data ->
updateUI(data)
}
}
}
// 配合 StateFlow / SharedFlow
lifecycleScope.launch {
viewModel.uiState
.repeatOnLifecycle(Lifecycle.State.STARTED)
.collect { state ->
render(state)
}
}
// 支持多个 Flow 同时收集
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch { viewModel.data.collect { /* */ } }
launch { viewModel.events.collect { /* */ } }
}
}
自定义 CoroutineScope
// 自定义 scope(通常配合 viewModelScope 使用)
class MyManager {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
fun doWork() {
scope.launch {
// 独立于 ViewModel 的协程
}
}
fun cleanup() {
scope.cancel()
}
}
// SupervisorJob:子协程失败不影响其他子协程
private val supervisor = SupervisorJob()
private val scope = CoroutineScope(supervisor + Dispatchers.Main)
scope.launch {
launch { throwException() } // 失败不影响其他
launch { anotherTask() } // 继续执行
}
// 注意: SupervisorJob 只对直接子协程有效
// 要让子协程失败不影响父协程,用 launch { ... }.launchIn(scope)
// 或使用 structured concurrency
全局作用域(慎用)
// GlobalScope:不推荐(无法取消,难测试)
GlobalScope.launch {
// 永远不会被自动取消
}
// GlobalScope 典型使用场景
// 库内部、后台任务、不与 UI 绑定的 long-running 任务
// Android 中很少使用
4. 通道 Channel
Channel 基础
import kotlinx.coroutines.channels.Channel
// Channel:协程间通信的管道(FIFO 队列)
// 类似于 BlockingQueue,但是非阻塞的
// 类型
val channel = Channel<Int>()
val channel2 = Channel<Int>(Channel.BUFFERED) // 带缓冲
val channel3 = Channel<Int>(Channel.RENDEZVOUS) // 零缓冲(默认)
// 发送和接收
suspend fun demo() {
val channel = Channel<String>()
launch {
channel.send("Hello")
channel.send("World")
channel.close() // 关闭 channel
}
// 接收
println(channel.receive()) // "Hello"
println(channel.receive()) // "World"
// channel.receive() // 挂起直到 close 或有新元素
}
// for 循环遍历
launch {
for (value in channel) {
println(value)
}
// 循环会在 channel.close() 且所有元素被消费后结束
}
Channel 类型
// 公平性:默认 Channel 是公平的(先到先服务)
// RENDEZVOUS(默认):发送和接收必须同时配对
// send() 会挂起直到有 receive() 等待
// receive() 会挂起直到有 send() 等待
// BUFFERED:固定容量缓冲
val bufferedChannel = Channel<Int>(capacity = 3)
bufferedChannel.send(1) // 不挂起直到 buffer 满
bufferedChannel.send(2)
bufferedChannel.send(3)
// bufferedChannel.send(4) // 挂起,直到 receive() 消费
// UNLIMITED:无限缓冲
val unlimited = Channel<Int>(Channel.UNLIMITED)
unlimited.send(1)
unlimited.send(100) // 永不挂起
// CONFLATED:超出容量时丢弃旧值
val conflated = Channel<Int>(Channel.CONFLATED)
conflated.send(1)
conflated.send(2) // 1 被丢弃
// 消费者只收到 2
Channel vs Flow
| 特性 |
Channel |
Flow |
| 用途 |
协程间通信 |
数据流处理 |
| 背压 |
支持 |
支持(缓冲 Flow) |
| 关闭 |
必须手动 close |
自动完成 |
| 语法 |
send/receive |
emit/collect |
| 热/冷 |
热(不订阅也发送) |
冷(订阅时才发送) |
| Android |
很少使用 |
大量使用 |
Channel 实战
// 场景:协程间事件通知
class EventBus {
private val _events = Channel<Event>(Channel.BUFFERED)
val events = _events.receiveAsFlow() // 转为 Flow 供外部收集
suspend fun send(event: Event) {
_events.send(event)
}
}
// 场景:并发任务结果收集
suspend fun collectResults(): List<Result> = coroutineScope {
val results = Channel<Result>()
// 并发执行多个任务
launch { results.send(processTask1()) }
launch { results.send(processTask2()) }
launch { results.send(processTask3()) }
// 收集所有结果
val collected = mutableListOf<Result>()
repeat(3) {
collected.add(results.receive())
}
collected
}
5. StateFlow / SharedFlow(热流)
StateFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
// StateFlow:状态容器,始终持有最新值
// 新订阅者立即收到当前值
// 适合:UI 状态管理
class ViewModel {
private val _uiState = MutableStateFlow<UiState>(UiState.Idle)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
fun load() {
_uiState.value = UiState.Loading // 更新状态
viewModelScope.launch {
try {
val data = repository.fetchData()
_uiState.value = UiState.Success(data)
} catch (e: Exception) {
_uiState.value = UiState.Error(e.message ?: "Error")
}
}
}
}
// Compose 中收集
@Composable
fun Screen(viewModel: MyViewModel) {
val uiState by viewModel.uiState.collectAsState()
when (uiState) {
is UiState.Idle -> Text("Idle")
is UiState.Loading -> CircularProgressIndicator()
is UiState.Success -> Text("Data: ${(uiState as UiState.Success).data}")
is UiState.Error -> Text("Error: ${(uiState as UiState.Error).message}")
}
}
SharedFlow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
// SharedFlow:事件流,无状态
// 新订阅者不收旧值,只收订阅后发出的值
// 适合:一次性事件(导航、Toast、Snackbar)
class ViewModel {
private val _events = MutableSharedFlow<Event>()
val events: SharedFlow<Event> = _events.asSharedFlow()
fun onButtonClick() {
viewModelScope.launch {
_events.emit(Event.ShowToast("操作成功"))
}
}
}
// Activity/Fragment 收集事件
lifecycleScope.launch {
viewModel.events
.repeatOnLifecycle(Lifecycle.State.STARTED)
.collect { event ->
when (event) {
is Event.ShowToast -> showToast(event.message)
is Event.Navigate -> navigateTo(event.route)
}
}
}
StateFlow vs SharedFlow
| 特性 |
StateFlow |
SharedFlow |
| 初始值 |
必须有初始值 |
无初始值 |
| 新订阅者收到 |
最新值 |
订阅后的新值 |
| replay |
始终 replay 最新值 |
可配置 replay 数量 |
| 适用场景 |
UI 状态 |
一次性事件 |
| 状态保持 |
✅ 有 |
❌ 无 |
| compose 支持 |
collectAsState() |
collectAsState()(需 replay=1) |
// SharedFlow 带 replay
val flow = MutableSharedFlow<String>(replay = 1)
// 订阅前发送的值会被新订阅者收到
flow.emit("Before subscribe")
flow.emit("After subscribe")
// 新订阅者收到 "After subscribe"(replay=1)
// SharedFlow 无 replay(默认 0)
val events = MutableSharedFlow<Event>()
// 新订阅者只收订阅后的事件
完整的事件+状态模式
// sealed class 状态定义
sealed class UiState<out T> {
object Idle : UiState<Nothing>()
object Loading : UiState<Nothing>()
data class Success<T>(val data: T) : UiState<T>()
data class Error(val message: String) : UiState<Nothing>()
}
// sealed class 事件定义
sealed class UiEvent {
data class ShowToast(val message: String) : UiEvent()
data class Navigate(val route: String) : UiEvent()
object NavigateBack : UiEvent()
}
// ViewModel
class MyViewModel(
private val repository: MyRepository
) : ViewModel() {
private val _uiState = MutableStateFlow<UiState<List<Item>>>(UiState.Idle)
val uiState: StateFlow<UiState<List<Item>>> = _uiState.asStateFlow()
private val _events = MutableSharedFlow<UiEvent>()
val events: SharedFlow<UiEvent> = _events.asSharedFlow()
fun load() {
viewModelScope.launch {
_uiState.value = UiState.Loading
runCatching {
repository.getItems()
}.onSuccess { items ->
_uiState.value = UiState.Success(items)
}.onFailure { e ->
_uiState.value = UiState.Error(e.message ?: "Unknown error")
}
}
}
fun onItemClick(item: Item) {
viewModelScope.launch {
_events.emit(UiEvent.Navigate("/detail/${item.id}"))
}
}
}
// Activity/Fragment 使用
class MyFragment : Fragment() {
private val viewModel: MyViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.uiState.collect { state ->
render(state)
}
}
launch {
viewModel.events.collect { event ->
handleEvent(event)
}
}
}
}
}
}
6. 冷流与热流
冷流 Cold Flow
// Flow 默认是冷流:订阅时才生成数据
val coldFlow = flow {
println("Start generating")
for (i in 1..3) {
delay(100)
emit(i)
}
println("Done generating")
}
// 未订阅时不执行
// coldFlow // 不输出
// 订阅时才执行
coldFlow.collect { value ->
println("Received: $value")
}
// 输出:
// Start generating
// Received: 1
// Received: 2
// Received: 3
// Done generating
// 两个订阅者分别触发两次执行
coldFlow.collect { println("A: $it") } // 重新开始
coldFlow.collect { println("B: $it") } // 再次重新开始
// 输出两组独立的 "Start generating... Done generating"
热流 Hot Flow
// StateFlow / SharedFlow 是热流
// 无论有多少订阅者,源头只执行一次
val stateFlow = MutableStateFlow(0)
val sharedFlow = MutableSharedFlow<String>()
// 订阅者 1
launch {
stateFlow.collect { println("Subscriber 1: $it") }
}
// 订阅者 2
launch {
stateFlow.collect { println("Subscriber 2: $it") }
}
// 仅触发一次
stateFlow.value = 42
// Subscriber 1: 42
// Subscriber 2: 42
// SharedFlow 同理
launch {
sharedFlow.collect { println("Shared 1: $it") }
}
launch {
sharedFlow.collect { println("Shared 2: $it") }
}
sharedFlow.emit("Hello")
// Shared 1: Hello
// Shared 2: Hello
// 只触发一次 emit,两个订阅者都收到
冷流转热流
// shareIn:冷流转热流(SharedFlow)
val sourceFlow = flow {
emitAll(dataSource)
}.shareIn(
scope = viewModelScope, // 共享作用域
started = SharingStarted.WhileSubscribed(5000), // 订阅才启动
replay = 1 // 新订阅者重放最近 1 条
)
// stateIn:冷流转 StateFlow
val sourceFlow = flow {
emitAll(dataSource)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = UiState.Idle // StateFlow 必须有初始值
)
// started 参数说明
SharingStarted.WhileSubscribed(5000)
// 订阅者存在时保持活跃
// 最后订阅者消失后 5 秒停止(减少不必要的资源消耗)
// 适用于:网络请求流
SharingStarted.Eagerly
// 立即开始,无论订阅者数量
// 适用于:内存状态、配置
SharingStarted.Lazily
// 第一个订阅者出现才开始
// 永远不停止
// 适用于:一次性数据
典型使用场景
// 场景一:数据库变更流(热流)
class MyDatabase {
private val _dataChanges = MutableSharedFlow<Change>()
val dataChanges: SharedFlow<Change> = _asSharedFlow()
suspend fun onDataChanged(change: Change) {
_dataChanges.emit(change)
}
}
// 场景二:用户输入搜索(冷流 + debounce)
class SearchViewModel {
private val _searchQuery = MutableStateFlow("")
val searchQuery: StateFlow<String> = _searchQuery.asStateFlow()
val searchResults: StateFlow<List<Result>> = _searchQuery
.debounce(300) // 等待 300ms 无新输入才执行
.filter { it.length >= 2 }
.distinctUntilChanged() // 与上次相同跳过
.flatMapLatest { query -> // 取消旧请求
api.search(query)
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = emptyList()
)
fun onQueryChanged(query: String) {
_searchQuery.value = query
}
}
// 场景三:定时刷新(热流)
class DataRepository {
private val refreshTrigger = MutableSharedFlow<Unit>(replay = 1)
val data: Flow<List<Item>> = refreshTrigger
.onStart { emit(Unit) } // 立即触发一次
.flatMapLatest { api.getItems() }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
suspend fun refresh() {
refreshTrigger.emit(Unit)
}
}
7. Flow 常用操作符
转换与过滤
// map:转换
numbers.map { it * 2 }
// filter:过滤
numbers.filter { it > 3 }
// take:取前 N 个
numbers.take(3)
// drop:跳过前 N 个
numbers.drop(3)
// mapNotNull:转换并过滤 null
items.mapNotNull { it.parent }
// flatMapLatest:只保留最新请求的结果
searchQuery.flatMapLatest { query ->
api.search(query)
}
时间相关
// debounce:防抖(等待无新输入)
.editText
.textChanges()
.debounce(300)
// distinctUntilChanged:跳过连续重复
editText.textChanges()
.distinctUntilChanged()
// delayEvent:延迟(不是 debounce)
flow.delay(100)
// buffer:缓冲(不阻塞)
flow.buffer(100)
// timeout:超时
flow.timeout(3000)
异常处理
// catch:捕获异常(不中断流)
dataFlow
.catch { e -> emit(DefaultData) } // 发送默认值
.collect { /* */ }
// retry:重试
dataFlow
.retry(3) // 重试 3 次
.collect { /* */ }
// retryWhen:条件重试
dataFlow
.retryWhen { cause, attempt ->
cause is NetworkException && attempt < 3
}
Lifecycle 配合
// repeatOnLifecycle 已内置,Flow 无需额外处理
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
flow.collect { /* */ }
}
}
// onEach:在 collect 之前执行
flow
.onEach { state = it }
.onEach { updateUI(it) }
.launchIn(viewModelScope) // 直接在 scope 中运行
// launchIn:替代 collect 自动绑定 lifecycle
flow
.onEach { updateUI(it) }
.catch { showError(it) }
.launchIn(viewModelScope)
// ⚠️ 不推荐:生命周期管理不如 repeatOnLifecycle 清晰
8. Compose State 联动
StateFlow → Compose
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@Composable
fun UserScreen(viewModel: UserViewModel = viewModel()) {
// collectAsState:自动将 StateFlow 转为 Compose State
val uiState by viewModel.uiState.collectAsState()
// uiState 是 UiState 类型(不是 StateFlow)
// 当 viewModel.uiState.value 变化时,Composable 自动重组
when (val state = uiState) {
is UiState.Loading -> LoadingView()
is UiState.Success -> SuccessView(state.data)
is UiState.Error -> ErrorView(state.message)
}
}
// collectAsState 带生命周期(推荐)
val uiState by viewModel.uiState
.collectAsState(
initial = UiState.Idle,
context = rememberCoroutineScope().coroutineContext
)
MutableStateFlow vs MutableState
// MutableStateFlow(ViewModel 推荐)
class ViewModel {
private val _state = MutableStateFlow(UiState.Idle)
val state: StateFlow<UiState> = _state.asStateFlow()
}
// Compose 收集
@Composable
fun Screen(viewModel: MyViewModel) {
val state by viewModel.state.collectAsState()
}
// MutableState(Compose 内直接使用)
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Count: $count")
}
}
// MutableStateFlow vs MutableState
// 场景一:ViewModel → UI(跨组件)→ MutableStateFlow
// 场景二:单个 Composable 内部 → MutableState
双向绑定
// ViewModel
class CounterViewModel : ViewModel() {
private val _count = MutableStateFlow(0)
val count: StateFlow<Int> = _count.asStateFlow()
fun increment() {
_count.value++
}
fun decrement() {
_count.value--
}
}
// Compose 单向数据流(推荐)
@Composable
fun CounterScreen(viewModel: CounterViewModel) {
val count by viewModel.count.collectAsState()
Column {
Text("Count: $count")
Row {
Button(onClick = { viewModel.decrement() }) {
Text("-")
}
Button(onClick = { viewModel.increment() }) {
Text("+")
}
}
}
}
// ViewModel 双向绑定(Android 原生风格)
// ViewModel 不适合双向绑定,Compose 单向数据流更清晰
快速对照表
| 概念 |
关键字 |
用途 |
| 挂起函数 |
suspend |
可在协程中挂起,不阻塞线程 |
| 启动协程 |
launch |
异步执行,不返回结果 |
| 启动协程 |
async |
异步执行,返回 Deferred |
| 主调度器 |
Dispatchers.Main |
UI 线程、Android 主线程 |
| IO 调度器 |
Dispatchers.IO |
网络、文件、数据库 |
| 默认调度器 |
Dispatchers.Default |
CPU 密集计算 |
| 作用域 |
viewModelScope |
ViewModel 生命周期绑定 |
| 作用域 |
lifecycleScope |
Activity/Fragment 生命周期 |
| 状态流 |
StateFlow |
热流、状态管理、有初始值 |
| 共享流 |
SharedFlow |
热流、事件通知、无初始值 |
| 通道 |
Channel |
协程间通信、FIFO |
| 冷流 |
flow { } |
订阅时生成数据 |
| 热流 |
shareIn/stateIn |
冷流转热流 |
| 重复生命 |
repeatOnLifecycle |
自动暂停/恢复 |
记忆口诀:
- 挂起不阻塞 → suspend
- UI 更新 → Dispatchers.Main
- IO 操作 → Dispatchers.IO
- 计算密集 → Dispatchers.Default
- ViewModel 状态 → StateFlow
- 一次性事件 → SharedFlow
- 协程通信 → Channel
- Flow 订阅 → repeatOnLifecycle + collect
- Compose 状态 → collectAsState()