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 在此回调
相关推荐
事圆则缓8 小时前
Android 崩溃优化与应用稳定性全解析:Crash、ANR、OOM 到线上治理
android
ZHOUPUYU8 小时前
PHP 高级技术实战:从原理到高并发架构落地
android·性能优化·php
stevenzqzq9 小时前
mvi的理解
android·compose
脚踏实地,坚持不懈!9 小时前
Android 电池健康度检测全流程(驱动 → 内核 → HAL → Framework)
android·linux
恋猫de小郭9 小时前
Genkit Dart 1.0 发布,Flutter 原生的 AI Agent 终于完整了
android·前端·flutter
迪康妍妍9 小时前
终端安全实战:用迪康终端安全管理系统实现U盘四分档管控与全量审计
android·运维·网络·安全·电脑
JackLam10 小时前
mobile-use 使用与接入第三方 LLM 网关完整指南OC
android·ai·mobile use
snotJam10 小时前
关于Uniapp的Android自定义基座使用
android·uni-app
TST-魚爷10 小时前
易视讯会议摄像头电视安装教程
android·电脑·钉钉·腾讯会议·zoom会议
墨天梦20 小时前
B17_LifecycleLiveData与Flow
android·kotlin