LaunchedEffect与Composable函数的区别(除协程作用域外)
LaunchedEffect 与普通 Composable 函数的核心区别(除协程作用域外)
结合你给出的代码示例,除了协程作用域之外,两者还有以下关键差异:
1. 重组触发的执行逻辑完全不同
- LaunchedEffect:它是 Compose 的副作用 API,仅当传入的key 参数(示例中的
progress)发生变化时,才会重新启动协程执行内部逻辑。即使所在的父 Composable 因为其他状态变化发生重组,只要 key 不变,它就不会重复执行内部代码。
比如你的示例里,只有progress的值改变时,才会进入协程执行onProgressCatch()和showIf,避免了无意义的重复调用。 - 普通 Composable(如
ListenProgress):只要所在父 Composable 触发重组,无论自身参数是否变化,函数体都会被重新执行。比如父 Composable 因为其他状态更新而重组,ListenProgress会被再次调用,导致onProgressCatch()和showIf重复执行,很可能引发不必要的副作用(比如多次弹出加载弹窗)。
2. 生命周期绑定与自动清理
- LaunchedEffect:其内部协程会自动绑定到所在 Composable 的生命周期:当 Composable 进入 Composition 时启动协程,退出 Composition(比如被移除界面)时自动取消协程,彻底避免内存泄漏或无效的后续操作。
- 普通 Composable:代码是同步执行的,没有自动的生命周期绑定机制。如果在里面执行异步操作(比如网络请求),需要手动处理生命周期销毁时的取消逻辑;即使是同步操作,也可能在 Composable 被销毁后因为重组残留执行逻辑,引发异常。
3. 职责定位与副作用规范
- LaunchedEffect:专门用于处理非 UI 渲染的副作用(比如调用外部工具类、异步操作、状态同步等),它的执行被 Compose 框架追踪,符合副作用执行的安全规范。
- 普通 Composable:核心职责是描述 UI 结构,如果在里面直接执行副作用(如你的
ListenProgress示例),会打破 Compose 的设计原则,导致副作用的执行不可控,增加调试难度和潜在 bug。
举个实际的坑:你的 ListenProgress 示例中,如果父 Composable 因为其他状态(比如一个文本的更新)触发重组,即使 progress 没有变化,onProgressCatch() 会被再次调用,GlobalLoader 也会重复执行 showIf,这显然不是预期行为;而用 LaunchedEffect 就不会出现这个问题,只有 progress 变化时才会执行。
内容的提问来源于stack exchange,提问作者Vadim Zhukov
相关产品推荐
相关产品推荐

