3、副作用

5 阅读5分钟

在 Jetpack Compose 中,副作用是指发生在可组合函数作用域之外的应用状态的变化。由于可组合项具有不可预测的重组特性、可能以不同顺序执行重组或发生可舍弃的重组,因此理想情况下,可组合项应该是无副作用的。然而,在某些情况下,副作用是必要的,例如触发一次性事件(如显示信息提示控件)或在满足特定状态条件时进入另一个屏幕。这些操作应从能感知可组合项生命周期的受控环境中调用。Jetpack Compose 提供了多种副作用 API,以帮助开发者在适当的时候处理这些操作。

关键术语

  • 效应:一种可组合函数,该函数不会发出界面,并且在组合完成后不会产生副作用。效应为在 Compose 中处理异步操作和生命周期相关任务提供了结构化的方式。

副作用 API 及其用例

  1. LaunchedEffect:在某个可组合项的作用域内运行挂起函数。

    • 用例:在可组合项的生命周期内执行工作并能够调用挂起函数。
    • 行为:当 LaunchedEffect 进入组合时,它会启动一个协程,并将代码块作为参数传递。如果 LaunchedEffect 退出组合,协程将取消。如果使用不同的键重组 LaunchedEffect,系统将取消现有协程,并在新的协程中启动新的挂起函数。
    • 示例:实现一个脉冲动画,该动画在用户交互或特定条件下触发,并在可组合项的整个生命周期内重复执行。
  2. rememberCoroutineScope:获取组合感知作用域,以便在可组合项外启动协程。

    • 用例:在可组合项外启动协程,但存在作用域限制,以便协程在退出组合后自动取消。
    • 行为:返回一个绑定到调用它的组合点的 CoroutineScope。调用退出组合后,作用域将取消。
    • 示例:在用户点击按钮时显示一个 Snackbar。
  3. rememberUpdatedState:在效应中引用某个值,该效应在值改变时不应重启。

    • 用例:捕获效应中的某个值,但如果该值发生变化,不希望效应重启。
    • 行为:创建对可捕获和更新的值的引用,适用于包含长期操作的效应。
    • 示例:实现一个在一段时间后消失的着陆屏,即使着陆屏重组,等待一段时间并发出时间已过通知的效应也不应该重启。
  4. DisposableEffect:需要清理的效应。

    • 用例:在键发生变化或可组合项退出组合后进行清理的附带效应。
    • 行为:如果 DisposableEffect 键发生变化,可组合项需要处理(执行清理操作)其当前效应,并通过再次调用效应进行重置。
    • 示例:根据 Lifecycle 事件发送分析事件,并在 Compose 中监听这些事件。
  5. SideEffect:将 Compose 状态发布为非 Compose 代码。

    • 用例:与非 Compose 管理的对象共享 Compose 状态。
    • 行为:在每次成功重组后执行相应效应。
    • 示例:将当前用户的用户类型传递给分析库,以便细分用户群体。
  6. produceState:将非 Compose 状态转换为 Compose 状态。

    • 用例:将外部订阅驱动的状态(如 Flow、LiveData 或 RxJava)引入组合。
    • 行为:启动一个协程,该协程将作用域限定为可将值推送到返回的 State 的组合。
    • 示例:从网络加载图像,并将加载状态转换为 Compose 状态。
  7. derivedStateOf:将一个或多个状态对象转换为其他状态。

    • 用例:当可组合项输入的变化频率超过需要的重组频率时,避免不必要的重组。
    • 行为:创建一个新的 Compose 状态对象,该对象只会按照需要进行更新。
    • 示例:根据滚动位置决定是否显示一个按钮,避免因滚动位置频繁变化而导致的不必要重组。
  8. snapshotFlow:将 Compose 的 State 转换为 Flow。

    • 用例:利用 Flow 运算符处理 State 变化。
    • 行为:在收集到块时运行该块,并发出从块中读取的 State 对象的结果。当读取的 State 对象之一发生变化时,如果新值与之前发出的值不相等,Flow 会向其收集器发出新值。
    • 示例:在用户滚动经过列表的首个项目时记录分析事件。

重启效应

Compose 中的一些效应(如 LaunchedEffect、produceState 或 DisposableEffect)会采用可变数量的参数和键来取消运行效应,并使用新的键启动一个新的效应。这些 API 的典型形式是:

EffectName(restartIfThisKeyChanges, orThisKey, orThisKey, ...) { block }
  • 最佳实践:效应代码块中使用的可变和不可变变量应作为参数添加到效应可组合项中。如果更改变量不应导致效应重启,则应将该变量封装在 rememberUpdatedState 中。

使用常量作为键

可以使用 true 等常量作为效应键,使其遵循调用点的生命周期。这具有有效的用例,但应审慎考虑,并确保确实需要这么做。


通过合理使用这些副作用 API,开发者可以在 Jetpack Compose 中有效地管理异步操作、生命周期和状态变化,从而构建出更加健壮和可维护的应用界面。