gpt4 book ai didi

android - 副作用问题 - Jetpack Compose 中的 LaunchedEffect 和 SideEffect

转载 作者:行者123 更新时间:2023-12-04 23:55:36 43 4
gpt4 key购买 nike

为什么 SideEffect 每次我的可组合项失效时都会被调用,但 LaunchedEffect 也不成立?

sealed class SomeState {
object Error:SomeState()
data class Content(): SomeState
}

class MyViewModel:ViewModel {
internal val response: MutableLiveData<SomeState> by lazy {
MutableLiveData<SomeState>()
}
}

// This is top-level composable, it wont be recomposed ever
@Composable
fun MyComposableScreen(
viewModel:MyVm,
launchActivity:()->Unit
){
val someDialog = remember { mutableStateOf(false) }

MyComposableContent()

GenericErrorDialog(someDialog = someDialog)

when (val state = viewModel.response.observeAsState().value) {
// Query 1
is Content -> LaunchedEffect(Unit) { launchActivity() }
Error -> {
// Query 2
// Gets called everytime this composable gets invalidated, for eg in case of TextField change, compiler is invalidating it.
// But if i change it to LaunchedEffect(Unit), invalidation has no effect,LaunchedEffect only gets called when there is new update to the LiveData. why?
SideEffect { someDialog.value = true}
}
}
}

// This is the content, which can be recomposed in case of email is changed
@Composable
fun MyComposableContent(
onEmailChange:(email) -> Unit,
email:String,
){
TextField(
email = email,
onValueChange = onEmailChange
)
}
我对 Query 1 和 Query 2 有疑问,它们都是顶级可组合的一部分,它们永远不会被重新组合,但可以失效,
when (val state = viewModel.response.observeAsState().value) { // observing to live-data
// Query 1
is Content -> LaunchedEffect(Unit) { launchActivity() }
Error -> {
// Query 2
SideEffect { someDialog.value = true}
}
}
如果是
Content -> LaunchedEffect(Unit) { launchActivity() }
我相信这应该没问题,因为我们只想在 LaunchedEffect 时启动 Activity 。是第一次组合的一部分,如果实时数据状态是内容,它将只是组合的一部分
我在第二种情况下遇到问题,
Error -> {
// Query 2
SideEffect { someDialog.value = true // shows a dialog}
}
如果 live-data 的最后状态, 是 viewModel 中的错误。每次我在 TextField 中进行更改时我的顶级 MyComposableScreen正在获取 invalidated (未重构)由 compose 编译器,并且由于实时数据的最后状态被设置为错误, SideEffect每次都在运行,这很好,因为它应该为每次成功的合成和重新合成运行。
但是,如果我从 SideEffect 更改它至 LaunchedEffect(Unit){someDialog.value = true}对话框不是每次都出现 MyComposableScreeninvalidated ,这就是期望的行为。
LaunchedEffect(Unit) gets called only if there live-data emits the new state again because of any UI-action.
但是,我不确定它背后的原因,为什么 LaunchedEffect(Unit){someDialog.value = true} 里面的代码在可组合获取 invalidated 后不触发但是里面的代码 SideEffect可组合无效后触发?

为了更清楚
我明白区别 SideEffect -> 在每一个成功的组合和重新组合上,如果它是其中的一部分 LaunchedEffect -> 当它进入合成并跨越重新合成时,除非键被更改。
但在上述情况下 - 特别是这段代码
@Composable
fun MyTopLevelComposable(viewModel:MyViewModel){

when (val state = viewModel.response.observeAsState().value) { // observing live-data state
is Content -> LaunchedEffect(Unit) { launchActivity() }
Error -> SideEffect { someDialog.value = true}
}
}
它永远不会被重组。再次调用此可组合对象的唯一原因可能是 compose 编译器使 View 无效。
我的查询是 -> 当 View /可组合无效时 SideEffect {someDialog.value = true}执行,因为它将再次通过组合而不是重新组合,因为 viewModel.response(这是实时数据)最后一个状态是 Error但是如果把它改成 LaunchedEffect(Unit) {someDialog.value = true}在可组合项失效后它不会再次执行。它只对 live-data. 发出的新状态作出 react
问题是为什么? Invalidate 应该重新开始组合,因为它是组合。不重新组合 LaunchedEffect行为应该类似于 SideEffect在这种情况下,因为两者都对 composition 使用react.

最佳答案

在 Compose 中,不存在使 View 无效这样的事情。
当您保留 when在与状态变量相同的范围内,更改状态变量会重构 when 的内容,但是当您将其移至单独的可组合时,仅更新 viewModel.response can recompose it - Compose 尝试尽可能减少要重构的 View 数量。LaunchedEffect(Unit)将在两种情况下重新运行:

  • 如果在先前的重组之一期间将其从 View 树中删除,然后再次添加。例如,如果您包装 LaunchedEffectif条件是第一个false然后 true .或者,在您的情况下,如果 when会选择Error ->is Content -> 之后,这也将删除 LaunchedEffect从 View 树。
  • 如果其中一个键传递给 LaunchedEffect已经改变。

  • 看起来你的问题是 LaunchedEffect新内容值进来时不会重新启动,要解决这个问题,您需要将此值作为 key 传递在 LaunchedEffect , 而不是 Unit :
    LaunchedEffect(state) { launchActivity() }

    关于android - 副作用问题 - Jetpack Compose 中的 LaunchedEffect 和 SideEffect,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71342736/

    43 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com