什么是 DisposableEffect 和 jetpack Compose 中的引擎盖下?

what is DisposableEffect and under the hood in jetpack compose?

提问人:NewPartizal 提问时间:7/25/2023 最后编辑:NewPartizal 更新时间:7/26/2023 访问量:950

问:

一段时间以来,我一直在试图了解什么是DisposableEffect以及它是如何工作的,所以我在互联网上搜索了一下,我看到大多数文档都是类似的解释,例如

DisposableEffect 是 Jetpack Compose 提供的强大工具, 允许您在可组合函数中执行副作用 当可组合物离开组合物时需要清理。你 可以使用键来控制何时调用回调函数。

我知道 DisposableEffect 像 LaunchedEffect 一样异步工作并基于键值,但是当 onDispose 方法工作时,您可以看到上面的定义

当可组合物离开组合物时需要清理

这句话可能定义了 onDispose 方法,所以在这种情况下,它意味着 onDispose 会起作用,但是当可组合项离开组合到处都这样写时,这意味着什么?我无法理解。

例如,我是这样做的

data class State(
    ...
    val isError:Int?=null,
    ...
)

用户界面

val errMsg = stringResource(id = R.string.error)
val savedMsg = stringResource(id = R.string.saved)

DisposableEffect(state.isError) {
        when (state.isError) {
            0 -> Toast.makeText(context, savedMsg, Toast.LENGTH_LONG).show()
            1 -> Toast.makeText(context, errMsg, Toast.LENGTH_LONG).show()
            else -> {}
        }
        onDispose {
            setIsError()
        }
    }

虚拟机

  fun setIsError(){
    _state.update {
        it.copy(
            isError = null,
        )
    }
}
 

那么,例如,在Dispose上何时运行?

这就是为什么我在这里每次用户按下按钮时都使用 onDisposableEffect,如果按下按钮时操作成功,则出现 isError 0,如果不是 1,我想在每次成功操作时都收到一条 Success 消息,但是一旦按下按钮并且操作成功,Success 消息不起作用,因为键值是 isError 仍然相同 0, 所以我使用 DisposableEffect 来解决这个问题,但正如我所说,我不知道细节,也没有完全理解

科特林 android-jetpack-compose 副作用

评论


答:

2赞 Jorn 7/25/2023 #1

请考虑以下示例代码:

@Composable
fun example() {
  var inComposition by remember { mutableStateOf(true) }
  if (inComposition) {
    DisposableEffect {
      ...
    }
  }
}

当变量从 到 时,将离开组合,从而运行其函数。DisposableEffectonDisposeinCompositiontruefalse

评论

0赞 NewPartizal 7/26/2023
你能从我的代码中解释一下吗?当 onDispose 在我的代码中运行时?当 state.isError 变为 true 时,DisposableEffect 会运行,它会检查它是 0 还是 1 并相应地输出 Toast 消息,并且因为 state.isError 再次为 true,我需要将其设置为 false,以便 DisposableEffect 可以再次工作,但在这种情况下,当 onDispose 方法运行时?我不明白这个.state.isError 保持 true,直到 onDispose 设置为 false
0赞 Jorn 7/26/2023
@NewPartizal我很难理解该代码。部分原因是我不确定如何工作(我只是做 Compose Desktop),部分原因是它使用了令人困惑的命名(例如 设置为 false)。ToastsetIsErrorerror
0赞 NewPartizal 7/26/2023
很抱歉造成混乱,我更新了我的代码。我希望这次的代码更清晰。
0赞 Thracian 7/25/2023 #2

DisposableEffect是一个函数,因为它观察记忆状态,而后者带有一个 .rememberLaunchedEffectcoroutineScope

dispose当块/可组合项由于 RememberObserver 的 onForgotten 函数而离开组合时,函数将被调用,如下所示。DisposableEffect

此实现类似于 LaunchedEffect 仅工作一次

@Composable
@NonRestartableComposable
fun DisposableEffect(
    key1: Any?,
    effect: DisposableEffectScope.() -> DisposableEffectResult
) {
    remember(key1) { DisposableEffectImpl(effect) }
}

LaunchedEffect

@Composable
@NonRestartableComposable
@OptIn(InternalComposeApi::class)
fun LaunchedEffect(
    key1: Any?,
    block: suspend CoroutineScope.() -> Unit
) {
    val applyContext = currentComposer.applyCoroutineContext
    remember(key1) { LaunchedEffectImpl(applyContext, block) }
}

处置工作原理部分是

private val InternalDisposableEffectScope = DisposableEffectScope()

private class DisposableEffectImpl(
    private val effect: DisposableEffectScope.() -> DisposableEffectResult
) : RememberObserver {
    private var onDispose: DisposableEffectResult? = null

    override fun onRemembered() {
        onDispose = InternalDisposableEffectScope.effect()
    }

    override fun onForgotten() {
        onDispose?.dispose()
        onDispose = null
    }

    override fun onAbandoned() {
        // Nothing to do as [onRemembered] was not called.
    }
}

这基本上就是记忆观察的生命周期。

当您移动到下一页时,退出条件块或将项目滚动出 LazyColumn/Row 的视口,onDispose 可用于观察块何时离开组合。

lazyColumn 是否在项目进入或离开屏幕时侦听事件