Rit*_*esh 5 android android-jetpack android-jetpack-compose
为什么每次我的可组合项失效时都会调用 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
)
}
Run Code Online (Sandbox Code Playgroud)
我怀疑查询 1 和查询 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}
}
}
Run Code Online (Sandbox Code Playgroud)
如果是
Content -> LaunchedEffect(Unit) { launchActivity() }
Run Code Online (Sandbox Code Playgroud)
LaunchedEffect我相信这应该没问题,因为我们只想在第一次组合的一部分时启动活动,并且如果实时数据状态为内容,它将只是组合的一部分
我在第二种情况下遇到了问题,
Error -> {
// Query 2
SideEffect { someDialog.value = true // shows a dialog}
}
Run Code Online (Sandbox Code Playgroud)
如果 的最后状态live-data是 viewModel 中的错误。每次我在TextField 顶层进行更改时,组合编译器MyComposableScreen都会获取(而不是重新组合),并且由于实时数据的最后状态被设置为错误,所以每次都在运行,这很好,因为它应该为每个成功的组合运行并重新组合。invalidatedSideEffect
但是,如果我将其更改为SideEffect对话框LaunchedEffect(Unit){someDialog.value = true}不会每次都显示MyComposableScreen,invalidated那就是所需的行为。
LaunchedEffect(Unit) gets called only if there live-data emits the new state again because of any UI-action.
Run Code Online (Sandbox Code Playgroud)
但是,我不确定其背后的推理,为什么内部的代码在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}
}
}
Run Code Online (Sandbox Code Playgroud)
它永远不会被重组。再次调用此可组合项的唯一原因可能是组合编译器使视图无效。
我的查询是 -> 当视图/可组合项失效时
SideEffect {someDialog.value = true} 执行,因为它将再次经历组合而不是重新组合,因为 viewModel.response(这是实时数据)最后的状态是Error
但是,如果将其更改为,LaunchedEffect(Unit) {someDialog.value = true} 则在可组合项失效后不会再次执行。它只对由live-data.
问题是为什么?无效应该再次开始合成,因为它是合成。不重新组合的LaunchedEffect 行为应该与SideEffect 这种情况类似,因为两者都对 做出反应composition。
Phi*_*hov 14
在 Compose 中,不存在使视图无效这样的事情。
当您将您的when状态变量保持在与状态变量相同的范围内时,更改状态变量会重新组合 的内容when,但是当您将其移动到单独的可组合项时,只有更新viewModel.response才能重新组合它 - Compose 尝试尽可能减少要重新组合的视图数量尽可能。
LaunchedEffect(Unit)将在两种情况下重新运行:
LaunchedEffect行if并且条件是 firstfalse和 then true。或者,在您的情况下,如果when选择Error ->after ,这也将从视图树中is Content ->删除。LaunchedEffectLaunchedEffect已更改。看来您的问题是LaunchedEffect当新内容值进来时不会重新启动,要解决此问题,您需要按key中的方式传递此值LaunchedEffect,而不是Unit:
LaunchedEffect(state) { launchActivity() }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
18752 次 |
| 最近记录: |