jetpack compose 副作用 SideEffect

SideEffect 用于将 Compose 内部状态安全地同步到外部非 Compose 世界。执行时机Composition 成功提交后、下一次重组之前。如果组合失败,SideEffect 不会执行。

场景 1:将 Compose 状态同步到外部对象

复制代码
@Composable
fun ChatScreen(viewModel: ChatViewModel) {
    val messages by viewModel.messages.collectAsState()
    val listState = rememberLazyListState()
    
    SideEffect {
        // 把滚动位置同步给 ViewModel 做持久化
        viewModel.saveScrollPosition(listState.firstVisibleItemIndex)
    }
}

场景 2:分析埋点

复制代码
@Composable
fun ProductPage(product: Product, tracker: AnalyticsTracker) {
    SideEffect {
        tracker.logEvent("product_view", mapOf("id" to product.id))
    }
}

注意事项

1、不要在 SideEffect 里修改 Compose State --- 会导致无限重组循环

2、适合"读"操作,不适合"写"操作 --- 它是同步出去,不是触发变化

3、如果需要异步操作,用 LaunchedEffect 而不是 SideEffect

源码

复制代码
// 1. SideEffect.kt 
@Composable
fun SideEffect(effect: () -> Unit) {
    currentComposer.recordSideEffect(effect)
}

和 snapshotFlow 的对比

对比项 SideEffect snapshotFlow
登记方式 recordSideEffect() → changes 列表 Snapshot.registerApplyObserver()
执行时机 Composition commit 成功 Global Snapshot apply 成功
失败处理 组合失败 → 丢弃 Snapshot apply 成功才回调
底层共同点 都依赖"记录→提交"模式,不是立即执行 都依赖"记录→提交"模式,不是立即执行

Snapshot 状态管理层 和 Composer UI 构建层

复制代码
Composition 层 (构建 UI 树)
    │
    │  依赖
    ▼
Snapshot 层 (管理状态读写)

Snapshot apply 发生在底层,Composition commit 发生在上层。一个改了状态值,一个改了 UI 树。

Snapshot apply 只是把数据标记为已确认,但 UI 树不一定刷新:

复制代码
// 场景:快速连续点击
button.onClick {
    count++  // → 触发 Snapshot apply(数据层)
    count++  // → 又触发一次 Snapshot apply
}
// 但 Composition 只会在下一帧跑一次重组
// → 两次 Snapshot apply,一次 Composition commit
对比项 Snapshot apply Composition commit
改了啥 State 值(变量层面) UI 节点树(LayoutNode 层面)
所在的层 Snapshot 系统 Composer 系统
触发者 MutableSnapshot.apply() 帧回调 + Composer
失败怎么办 几乎不会失败(纯数据合并) 可能失败(异常/中断 → 丢弃整棵树)
观察者 registerApplyObserver recordSideEffect
典型案例 snapshotFlow 在此回调 SideEffect 在此回调
相关推荐
ImTryCatchException19 分钟前
Android 画中画(PiP)小窗播放:怎么做、以及它到底是怎么工作的
android·pip
YB13754 小时前
Kotlin 三类关键字
kotlin
flower_drop10 小时前
基于 WebUSB 与 CDP:在浏览器端实现 Android 设备通信与无证书抓包实践
android·chrome·测试工具·adb·bug·edge浏览器
撩得Android一次心动12 小时前
Jetpack Compose 知识点整理1【个人用】
android·学习·kotlin·android jetpack·compose
ForteScarlet13 小时前
Kotlin 2.4.20 现已发布,新特性多不多?
android·java·开发语言·开源·kotlin·jetbrains
JMchen12313 小时前
Cursor高阶玩法:.cursorrules编写与Spec-Driven开发实战,把AI调教成专属结对编程搭档
人工智能·vscode·kotlin·cursor·结对编程·spec-driven·.cursorrules
方白羽15 小时前
Android Studio 自动国际化插件:SmartI18n
android·android studio·intellij idea
码农coding17 小时前
android12 状态栏图标的加载流程
android
hai_android18 小时前
Kotlin 协程作用域源码剖析
android·kotlin
Yeyu18 小时前
Android 画中画(PiP)小窗播放:怎么做、以及它到底是怎么工作的
android