Loading...
Loading...
Compare original and translation side by side
| Need | API |
|---|---|
| Publish Compose state to non-Compose code after every successful recomposition | |
| Register/unregister a listener, callback, observer, or resource | |
| Run suspending, deferred, or keyed one-shot work | |
| Launch suspending work from a user event callback | |
| Convert Compose snapshot reads into a Flow inside a coroutine | |
| 需求 | API |
|---|---|
| 在每次成功重组后将Compose状态同步到非Compose代码 | |
| 注册/注销监听器、回调、观察者或资源 | |
| 执行挂起、延迟或基于键的一次性操作 | |
| 从用户事件回调中启动挂起操作 | |
| 在协程中将Compose快照读取转换为Flow | 在 |
// ✅ Restart collection when userId changes
LaunchedEffect(userId) {
repository.events(userId).collect { event -> handle(event) }
}
// ❌ Unit hides a changing input; collection keeps using the first userId
LaunchedEffect(Unit) {
repository.events(userId).collect { event -> handle(event) }
}userIdscreenIdlifecycleOwnerfocusRequesterstateviewModel// ✅ 当userId变化时重启收集操作
LaunchedEffect(userId) {
repository.events(userId).collect { event -> handle(event) }
}
// ❌ Unit隐藏了变化的输入;收集操作会一直使用第一个userId
LaunchedEffect(Unit) {
repository.events(userId).collect { event -> handle(event) }
}userIdscreenIdlifecycleOwnerfocusRequesterstateviewModelrememberUpdatedState@Composable
fun Timeout(onTimeout: () -> Unit) {
val latestOnTimeout by rememberUpdatedState(onTimeout)
LaunchedEffect(Unit) {
delay(1_000)
latestOnTimeout()
}
}onTimeoutonStartonStoprememberUpdatedState// BAD: userId changes should restart the collection, not update a captured value.
val latestUserId by rememberUpdatedState(userId)
LaunchedEffect(Unit) {
repository.events(latestUserId).collect { event -> handle(event) }
}
// GOOD: the collection lifecycle follows userId.
LaunchedEffect(userId) {
repository.events(userId).collect { event -> handle(event) }
}rememberUpdatedStateStatecompose-state-deferred-readsrememberUpdatedState@Composable
fun Timeout(onTimeout: () -> Unit) {
val latestOnTimeout by rememberUpdatedState(onTimeout)
LaunchedEffect(Unit) {
delay(1_000)
latestOnTimeout()
}
}onTimeoutonStartonStoprememberUpdatedState// 错误:userId变化应重启收集操作,而不是更新捕获的值。
val latestUserId by rememberUpdatedState(userId)
LaunchedEffect(Unit) {
repository.events(latestUserId).collect { event -> handle(event) }
}
// 正确:收集操作的生命周期跟随userId。
LaunchedEffect(userId) {
repository.events(userId).collect { event -> handle(event) }
}rememberUpdatedStateStatecompose-state-deferred-readsLaunchedEffectLaunchedEffect(events) {
events.collect { event ->
snackbarHostState.showSnackbar(event.message)
}
}collectAsStateWithLifecycle()collectAsState()compose-state-holder-ui-splitcollectAsState()snapshotFlowLaunchedEffect(listState) {
snapshotFlow { listState.firstVisibleItemIndex }
.distinctUntilChanged()
.collect { index -> analytics.visibleIndex(index) }
}snapshotFlow { ... }.map { ... }collectLaunchedEffectLaunchedEffect(events) {
events.collect { event ->
snackbarHostState.showSnackbar(event.message)
}
}collectAsStateWithLifecycle()collectAsState()compose-state-holder-ui-splitcollectAsState()snapshotFlowLaunchedEffect(listState) {
snapshotFlow { listState.firstVisibleItemIndex }
.distinctUntilChanged()
.collect { index -> analytics.visibleIndex(index) }
}collectsnapshotFlow { ... }.map { ... }rememberCoroutineScope()@Composable
fun SaveButton(snackbarHostState: SnackbarHostState) {
val scope = rememberCoroutineScope()
Button(
onClick = {
scope.launch {
snackbarHostState.showSnackbar("Saved")
}
},
) {
Text("Save")
}
}LaunchedEffectrememberCoroutineScope()@Composable
fun SaveButton(snackbarHostState: SnackbarHostState) {
val scope = rememberCoroutineScope()
Button(
onClick = {
scope.launch {
snackbarHostState.showSnackbar("Saved")
}
},
) {
Text("Save")
}
}LaunchedEffectDisposableEffect@Composable
fun ObserveLifecycle(owner: LifecycleOwner, observer: LifecycleObserver) {
DisposableEffect(owner, observer) {
owner.lifecycle.addObserver(observer)
onDispose {
owner.lifecycle.removeObserver(observer)
}
}
}onDisposeDisposableEffect@Composable
fun ObserveLifecycle(owner: LifecycleOwner, observer: LifecycleObserver) {
DisposableEffect(owner, observer) {
owner.lifecycle.addObserver(observer)
onDispose {
owner.lifecycle.removeObserver(observer)
}
}
}onDispose| Mistake | Fix |
|---|---|
| Network request directly in the composable body | Usually move to a ViewModel/state holder; use |
| Analytics property written from the composable body | Use |
| Impression/event logged from the composable body | Use |
| Key by |
| Hidden lifecycle bug |
| Long-lived effect invokes an old callback after recomposition | Stale capture |
| Key by the specific property |
| Usually |
Listener added in | Use |
Launching from click by setting | Use |
| 错误 | 修复方案 |
|---|---|
| 在可组合函数主体中直接发起网络请求 | 通常移至ViewModel/状态持有者;仅将 |
| 在可组合函数主体中写入分析属性 | 当需要在每次成功重组后发布时,使用 |
| 在可组合函数主体中记录曝光/事件 | 当需要针对该键运行一次时,使用 |
| 以 |
使用 | 隐藏的生命周期问题 |
| 长期运行的effect在重组后调用旧的回调 | 过时捕获 |
| 以特定属性作为键 |
| 通常使用 |
在 | 使用 |
通过设置 | 在点击回调中使用 |
LaunchedEffect(Unit)rememberUpdatedStateLaunchedEffect(Unit)rememberUpdatedState