Jetpack Compose 中,DisposableEffect、LaunchedEffect 和 sideEffect 区别和用途

发布于:2025-06-08 ⋅ 阅读:(21) ⋅ 点赞:(0)

在 Jetpack Compose 中,DisposableEffectLaunchedEffect 和 sideEffect 都是用于处理副作用(Side Effects)的 API,但它们的用途和触发时机不同。以下是它们的核心概念和区别:

1. 副作用(Side Effect)是什么?

副作用是指 Composable 函数中与界面渲染无关的操作,例如:

  • 发起网络请求

  • 订阅/取消订阅数据流

  • 修改外部变量或状态

  • 访问 Android 系统 API(如权限、生命周期)

由于 Composable 函数可能会频繁重组(Recomposition),副作用需要被可控地管理,避免重复执行或资源泄漏。

2. 三者的对比

API 用途 触发时机 清理机制 适用场景
LaunchedEffect 在 Composable 中启动一个协程,执行挂起函数(如异步任务)。 当 key 变化时,会取消之前的协程并重新启动。 自动取消协程 一次性异步操作(如网络请求、动画)。
DisposableEffect 执行需要清理的资源操作(如监听器、订阅)。 当 key 变化时,先执行清理逻辑,再重新执行副作用。 需手动清理(onDispose 需要释放资源的操作(如广播、RxJava 订阅)。
sideEffect 在每次成功重组后执行的非阻塞操作,不依赖重组是否跳过。 每次重组后(即使其他部分跳过重组)。 更新外部状态(如 Analytics 日志、非关键状态同步)。

3. 详细说明与代码示例

(1) LaunchedEffect
  • 用途:在 Composable 中安全启动协程,适合异步任务。

  • 特点

    • 自动取消:当 key 变化或 Composable 退出时,协程会被取消。

    • 必须指定 key(用于控制重启条件)。

@Composable
fun TimerDemo() {
    var time by remember { mutableStateOf(0) }
    LaunchedEffect(Unit) { // 传入 Unit 表示只启动一次
        while (true) {
            delay(1000)
            time++
        }
    }
    Text("Time: $time")
}
(2) DisposableEffect
  • 用途:管理需要手动释放的资源(如监听器、订阅)。

  • 特点

    • 必须调用 onDispose 清理资源。

    • key 变化时,先执行 onDispose,再重新初始化。

  • @Composable
    fun SensorDemo() {
        val sensorManager = remember { getSystemService(Context.SENSOR_SERVICE) as SensorManager }
        var data by remember { mutableStateOf(0f) }
    
        DisposableEffect(Unit) {
            val listener = object : SensorEventListener {
                override fun onSensorChanged(event: SensorEvent) {
                    data = event.values[0]
                }
                override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
            }
            sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL)
            
            onDispose { // 必须清理!
                sensorManager.unregisterListener(listener)
            }
        }
        Text("Sensor value: $data")
    }
(3) sideEffect
  • 用途:在重组后执行非阻塞操作,通常用于与 Compose 无关的状态同步。

  • 特点

    • 每次重组后都会执行(即使其他部分跳过了重组)。

    • 无清理机制,适合轻量级操作。

@Composable
fun AnalyticsButton(clicked: Boolean) {
    Button(onClick = { /* ... */ }) {
        Text("Click Me")
    }
    sideEffect {
        if (clicked) {
            logAnalyticsEvent("ButtonClicked") // 记录日志
        }
    }
}

4. 关键区别总结

场景 LaunchedEffect DisposableEffect sideEffect
异步任务 ✅(协程)
需要清理的资源 ✅(监听器、订阅)
重组后状态同步 ✅(日志、统计)
自动取消/清理 ✅(协程) ✅(需手动 onDispose

5. 如何选择?

  • 需要协程? → LaunchedEffect

  • 需要释放资源? → DisposableEffect

  • 只需在重组后同步状态? → sideEffect

通过合理使用这些 API,可以避免副作用导致的性能问题或内存泄漏。


网站公告

今日签到

点亮在社区的每一天
去签到