当视图模型中的状态发生变化时,为啥路由的 Composable 会重新组合?

Posted

技术标签:

【中文标题】当视图模型中的状态发生变化时,为啥路由的 Composable 会重新组合?【英文标题】:Why does the Composable for the route recompose when state changes in the view model?当视图模型中的状态发生变化时,为什么路由的 Composable 会重新组合? 【发布时间】:2021-08-28 17:31:17 【问题描述】:

TLDR:问题是,当composable 不依赖于我的 ViewModel 中更新的值时,为什么我会在 logcat 中同时看到“Route Composable”和“Home Screen”?我希望只看到“主屏幕”,因为这是唯一使用 ViewModel 中的状态值的组合。

我最近在生产应用程序中遇到了一种情况,我的路由组合被调用了两次,导致 UI 出现轻微闪烁。在深入研究了几个小时后,我发现闪烁的原因是在将 ViewModel 提供给我的撰写屏幕的路线中使用了hiltViewModel。我进一步挖掘发现,只要 ViewModel 中的状态发生变化,Route 的可组合对象就会被重新组合。我会认为只有可组合的子组件会重新组合,因为它是唯一使用状态值的子组件?

完整的项目是here,但基本的 Compose 代码如下所示。 (我尽可能多地删除了样板文件)

@Composable
fun AppNav() 
    val navController = rememberNavController()

    NavHost(navController = navController, startDestination = Screen.Home.route) 
        addHome()
    


private fun NavGraphBuilder.addHome() 
    composable(Screen.Home.route) 
        Log.i("Home", "Route Composable")
        val homeViewModel = hiltViewModel<HomeViewModel>()
        HomeScreen(
            homeCount = homeViewModel.homeCount,
            updateCount =  homeViewModel.updateCount() ,
        )
    


@Composable
fun HomeScreen(
    homeCount: Int,
    updateCount: () -> Unit,
) 
    Log.i("Home", "Home Screen")
    Column(modifier = Modifier.fillMaxSize()) 
        Spacer(modifier = Modifier.height(25.dp))
        Button(onClick =  updateCount() ) 
            Text("Increment count")
        
        Spacer(modifier = Modifier.height(25.dp))
        Text("Count is: $homeCount")
    

【问题讨论】:

【参考方案1】:

在仔细阅读documentation 并在Slack Channel 中确认后,我发现核心问题是对 State 如何与 Compose 一起工作的误解。我在想它只改变了状态被消耗的可组合,而实际上任何包含(读取)状态的可组合将在状态改变时重新组合。我的示例中的代码与做的基本相同:

composable(Screen.Home.route) 
    Log.i("Home", "Route Composable")
    var homeCount by remember  mutableStateOf(0) 
    HomeScreen(
        homeCount = homeCount,
        updateCount =  homeCount++ ,
    )

State 是像这个版本一样直接在 Composable 中更新,还是像原始代码一样在 ViewModel 中更新 State 没有区别。无论哪种方式,包含 State 的 Composable 都会重新组合。

任何时候更新状态都会发生重组。

对 value 的任何更改都会安排读取 value 的任何可组合函数的重组。

【讨论】:

【参考方案2】:

我想你需要看看在导航到不同的路线时如何使用saveStaterestoreState。 这是一篇关于这件事的文章: https://developer.android.com/jetpack/compose/navigation#bottom-nav

【讨论】:

感谢您的建议,但问题不在于在 Composables 中保存/恢复状态,而是关于当 ViewModel 中的状态发生变化时 Composables 将如何反应。有没有办法可以更新原始问题以更具体地说明问题?

以上是关于当视图模型中的状态发生变化时,为啥路由的 Composable 会重新组合?的主要内容,如果未能解决你的问题,请参考以下文章

为啥滚动后我的单元格中的图标会发生变化? [复制]

为啥android webview中的css属性会发生变化

为啥模型的准确性会发生变化?

在路由加载时将模型加载到 redux 存储的最佳方法

react监听仓库数据变化

当节点后端(MongoDB)中的状态发生变化时通知 Angular 前端