compose中 SideEffect概念以及作用

SlideEffect排在第三位执行,一般是函数中最后一行同步代码执行完,再执行。

2025-12-26 14:22:10.974 6006-6006 Exp4 com.example.composestudy D 1️⃣ 函数体:data=初始

2025-12-26 14:22:10.974 6006-6006 Exp4 com.example.composestudy D 3️⃣ 函数体继续:data=初始

2025-12-26 14:22:10.980 6006-6006 Exp4 com.example.composestudy D 2️⃣ SideEffect 立即执行:data=初始

先给一个绝对准确的结论(可以直接记住)

SideEffect 的代码是在 Composable 函数执行"期间被记录",
但真正执行是在:本次重组完成、UI 变更已提交之后。

所以答案是:

  • 不是"函数最后一行执行完立刻执行"
  • 也不是"UI 已经绘制到屏幕之后"
  • "Compose 完成一次成功重组并提交变更之后,在同一帧内执行"

一、为什么日志"看起来像顺序执行"?(这是关键)

看到的是类似这种日志顺序,对吧 👇

kotlin 复制代码
@Composable
fun Demo() {
    Log.d("TAG", "A")

    SideEffect {
        Log.d("TAG", "SIDE")
    }

    Log.d("TAG", "B")
}

日志是:

text 复制代码
A
B
SIDE

或者有时会感觉:

"SideEffect 好像就是在函数里顺着跑的"

原因只有一个:

SideEffect 在函数执行时"被注册",不是立即执行

Compose 在函数执行阶段做的是:

text 复制代码
执行 Composable 函数
 ├─ Log("A")
 ├─ 注册一个 SideEffect(放进 effect 队列)
 ├─ Log("B")
函数执行结束

👉 此时 SideEffect 还没执行


二、真正的时间线(非常重要,给"底层级"顺序)

我们用一个真实的时序图来看一次重组:

text 复制代码
① 执行 Composable 函数(重组)
   ├─ 普通代码立即执行(Log、if、remember)
   ├─ SideEffect 只是被"登记"
   └─ UI 描述树被重新计算

② Compose 内部:
   ├─ 对比新旧 UI 树(diff)
   ├─ 确认这次重组是"成功的"
   └─ 提交 UI 变更(commit)

③ 执行 SideEffect(同步)

👉 SideEffect 永远在第③步


三、那为什么不是"UI 绘制完成之后"?(非常关键的区分)

Compose 有三层概念,很多人混在一起了:

层级 含义
重组(Recomposition) 重新计算 UI 描述
提交(Commit) 应用 UI 变更
绘制(Draw) 真正画到屏幕

SideEffect 的位置是:

text 复制代码
重组完成 ✅
提交完成 ✅
绘制开始 ❌ / 或正在同一帧调度中

SideEffect 不保证"画完了"

它保证的是:UI 状态已经稳定,不会被回滚


四、为什么 Compose 要这么设计?(设计动机)

核心原因一句话:

副作用是不可回滚的,而 UI 计算是可回滚的

如果:

  • UI 还在计算
  • 中途又被新的状态打断

👉 那这次 UI 计算会被丢弃

👉 但 SideEffect 如果已经执行,就会造成世界状态错乱

所以 Compose 的保证是:

只有当这次重组"确定要生效"时,才执行 SideEffect


五、再回答那句非常关键的直觉判断

"SideEffect 的执行似乎没有受到其他干扰"

这是对的,而且是刻意设计的

  • 它不会被中途 cancel
  • 不会被 recomposition 打断
  • 不受 key 控制
  • 只要这次重组提交了,就一定会执行一次

但注意 ⚠️:

每一次成功重组 → 执行一次 SideEffect


六、用一句"工程级"话术帮彻底定型

以后可以这样理解、这样跟别人说:

SideEffect 不是 Composable 代码的一部分,
而是"在这次 UI 更新已经确定之后,对外部世界做的同步动作"。


七、和 LaunchedEffect / DisposableEffect 的时序对比(加深理解)

API 注册时机 执行时机
SideEffect Composable 执行时 重组提交后(同步)
LaunchedEffect Composable 执行时 重组提交后(启动协程)
DisposableEffect Composable 执行时 进入 / 离开组合

八、现在已经到了 Compose 的「内核理解层」

能问出这个问题,说明已经在思考:

  • Compose 到底什么时候"算 UI"
  • 什么时候"影响世界"

这已经不是 API 层的问题了,是调度模型


二 示例

复制代码
@Composable
    fun ExperimentScreen4() {
        var data by remember { mutableStateOf("初始") }

        Log.d("Exp4", "1️⃣ 函数体:data=$data")

        // 同步 - 立即执行
        SideEffect {
            Log.d("Exp4", "2️⃣ SideEffect 立即执行:data=$data")
            data = "SideEffect 修改"  // 这行不会触发重组
        }

        // 异步 - 后台执行
        LaunchedEffect(Unit) {
            Log.d("Exp4", "4️⃣ LaunchedEffect 后台执行开始")
            delay(100)
            Log.d("Exp4", "5️⃣ LaunchedEffect 延迟后:data=$data")
        }

        Log.d("Exp4", "3️⃣ 函数体继续:data=$data")

        Text("当前数据:$data")
    }

2025-12-26 14:22:10.974  6006-6006  Exp4                    com.example.composestudy             D  1️⃣ 函数体:data=初始
2025-12-26 14:22:10.974  6006-6006  Exp4                    com.example.composestudy             D  3️⃣ 函数体继续:data=初始
2025-12-26 14:22:10.980  6006-6006  Exp4                    com.example.composestudy             D  2️⃣ SideEffect 立即执行:data=初始
2025-12-26 14:22:11.087  6006-6006  Exp4                    com.example.composestudy             D  4️⃣ LaunchedEffect 后台执行开始
2025-12-26 14:22:11.091  6006-6006  Exp4                    com.example.composestudy             D  1️⃣ 函数体:data=SideEffect 修改
2025-12-26 14:22:11.091  6006-6006  Exp4                    com.example.composestudy             D  3️⃣ 函数体继续:data=SideEffect 修改
2025-12-26 14:22:11.095  6006-6006  Exp4                    com.example.composestudy             D  2️⃣ SideEffect 立即执行:data=SideEffect 修改
2025-12-26 14:22:11.188  6006-6006  Exp4                    com.example.composestudy             D  5️⃣ LaunchedEffect 延迟后:data=SideEffect 修改
相关推荐
stevenzqzq14 小时前
Compose 中最常用的布局** —— Box / Row / Column / ConstraintLayout教程
compose
stevenzqzq20 小时前
LaunchedEffect的作用和如何使用
compose
MengFly_2 天前
Compose案例 — Android 调用系统相机拍照
android·kotlin·compose
氦客2 天前
Android Compose : 传统View在Compose组件中的等价物
android·compose·jetpack·对比·传统view·等价物·compose组件
氦客3 天前
UI编程的发展史 : 结合命令式UI和声明式UI
android·compose·声明式ui·ui编程·命令式ui·ui编程发展史·标记语言
stevenzqzq5 天前
Compose Navigation 时序图
compose
stevenzqzq5 天前
Compose 状态 / 协程 总图
compose
儿歌八万首8 天前
Jetpack Compose 动画实战:让你的 UI 动起来
android·kotlin·动画·compose
儿歌八万首10 天前
Jetpack Compose 自定义布局解析
kotlin·compose·自定义布局
zFox10 天前
二、Kotlin高级特性以及Compose状态驱动UI
ui·kotlin·compose