如何在Composable函数中正确创建ViewModel以避免代码重复执行问题
问题原因
你观察到的两次日志打印是Jetpack Compose的正常重组机制导致的:hiltViewModel() 是带副作用的Composable调用,首次执行时会完成ViewModel的实例化,这个过程会触发当前ItemDetailsScreen的二次重组,因此顶层的Log语句会执行两次。当你注释掉ViewModel参数后,没有触发二次重组的来源,所以只会执行一次初始重组。
Compose本身设计就是可以按需多次执行重组,只要保证重组逻辑是幂等的就不会有问题,但你需要把带副作用的逻辑和UI渲染逻辑拆分。
解决方案
如果要让日志、数据请求这类仅需执行一次的逻辑不随重组重复运行,使用LaunchedEffect包裹即可,绑定固定Key(比如当前页面的itemId),只要Key不变,内部逻辑就只会在页面首次进入时执行一次:
fun ItemDetailsScreen( navController: NavController, itemId: String, viewModel: ItemDetailsViewModel = hiltViewModel() ) { // 绑定itemId作为Key,仅当itemId变化时才重新执行内部代码 LaunchedEffect(key1 = itemId) { Log.d(TAG, itemId) // 页面数据请求逻辑也放在这里,避免重复请求 viewModel.getItem(itemId) } // 原有UI渲染逻辑保持不变 }
如果有其他需要和重组生命周期解绑的逻辑,也可以根据场景选择SideEffect、DisposableEffect等 Compose 副作用API处理,不要直接写在Composable的顶层作用域。
内容的提问来源于stack exchange,提问作者Always Learner
相关产品推荐
相关产品推荐

