LaunchedEffect的作用和如何使用

一句话答案(先给结论)

LaunchedEffect 不是因为"要异步"才用的

而是因为:

👉 在 Composable 里做了一件"不能在重组时重复做、且必须绑定生命周期的事"


这段代码里,真正关键的是这一句:

kotlin 复制代码
viewModel.event.collect { event -> ... }

一、看清楚:collect 本身就是「挂起函数」

虽然你觉得"没异步逻辑",但:

kotlin 复制代码
viewModel.event.collect { ... }

本质是:

kotlin 复制代码
suspend fun collect(...)

也就是说:

这行代码只能在协程里运行

你之所以"没感觉到异步",是因为:

  • collect挂起当前协程
  • 等待 event 发射
  • 来一个,处理一个

它不是"起后台线程",

而是一个 长期存在的监听协程


二、那为什么不能直接写在 Composable 里?

❌ 错误示例(编译都不让)

kotlin 复制代码
@Composable
fun HomeScreen(...) {
    viewModel.event.collect { } // ❌ suspend
}

因为:

Composable ≠ suspend function


三、那为什么不用 rememberCoroutineScope

你可能会想到:

kotlin 复制代码
val scope = rememberCoroutineScope()
scope.launch {
    viewModel.event.collect { }
}

❌ 这在工程上是危险写法

原因 1️⃣:重组会重复 launch

kotlin 复制代码
@Composable
fun HomeScreen() {
    val scope = rememberCoroutineScope()
    scope.launch { ... } // ❌ 每次重组都会 launch
}

结果:

监听被注册 N 次

导航 / Toast 被触发 N 次


原因 2️⃣:生命周期不清晰

  • Composable 离开 Composition
  • 这个 scope 可能还活着
  • event 继续被消费

四、LaunchedEffect 真正解决的是什么?

1️⃣ 只启动一次(或按 key)

kotlin 复制代码
LaunchedEffect(Unit) { ... }

语义是:

当这个 Composable 进入 Composition 时启动

重组不会重新启动


2️⃣ 自动 cancel

复制代码
Composable 离开 Composition
      ↓
LaunchedEffect 协程自动 cancel

不泄漏

不重复

不脏


3️⃣ 语义非常明确

kotlin 复制代码
LaunchedEffect(Unit) {
    viewModel.event.collect { ... }
}

读代码的人一眼就知道:

这是一个"副作用监听"


五、那你说得对的一点是什么?

你说:

看起来 LaunchedEffect 里面的代码没有进行异步

这句话一半对,一半错

对的部分

  • 没有显式 delay
  • 没有 withContext(IO)
  • 没有并发计算

错的部分

  • collect挂起的
  • 它会 一直等待数据
  • 这是典型的 长期协程

六、换一种写法,你立刻能看懂它在"干嘛"

kotlin 复制代码
LaunchedEffect(Unit) {
    // 启动一个监听 ViewModel 事件的协程
    viewModel.event.collect { event ->
        handleEvent(event)
    }
}

你就会发现:

这是一个"生命周期绑定的监听器"


七、对比三种写法(非常重要)

写法 是否正确 原因
直接 collect suspend 不能用
rememberScope.launch ⚠️ 易重复 / 泄漏
LaunchedEffect 生命周期安全

八、什么时候「必须」用 LaunchedEffect?

只要满足 任意一条

  • 要调用 suspend 函数
  • 要监听 Flow
  • 要做一次性副作用
  • 不能因为重组重复执行
  • 需要跟随 Composable 生命周期

👉 就该用 LaunchedEffect


九、最后一句"本质解释"(最重要)

Compose 的函数不是"一次执行"

LaunchedEffect 是在告诉 Compose:

"这段逻辑不是 UI 描述,而是副作用

请只在合适的生命周期点执行一次"


用一句话回答你最初的问题

不是因为要异步才用 LaunchedEffect

而是因为:

collect 是一个长期挂起的监听

必须放在一个「不会随重组反复执行」

且「生命周期安全」的协程容器里


相关推荐
MengFly_1 天前
Compose案例 — Android 调用系统相机拍照
android·kotlin·compose
氦客2 天前
Android Compose : 传统View在Compose组件中的等价物
android·compose·jetpack·对比·传统view·等价物·compose组件
氦客2 天前
UI编程的发展史 : 结合命令式UI和声明式UI
android·compose·声明式ui·ui编程·命令式ui·ui编程发展史·标记语言
stevenzqzq4 天前
Compose Navigation 时序图
compose
stevenzqzq4 天前
Compose 状态 / 协程 总图
compose
儿歌八万首7 天前
Jetpack Compose 动画实战:让你的 UI 动起来
android·kotlin·动画·compose
儿歌八万首9 天前
Jetpack Compose 自定义布局解析
kotlin·compose·自定义布局
zFox9 天前
二、Kotlin高级特性以及Compose状态驱动UI
ui·kotlin·compose
儿歌八万首11 天前
Jetpack Compose :封装 MVVM 框架
android·kotlin·compose