Android Compose中两种ViewModel初始化方式为何状态保留不同
关于Compose中ViewModel状态保留的疑问与解答
我的可组合函数
@Composable fun CounterScreen(viewModel: MyViewModel = viewModel()) { val uiState by viewModel.uiState.collectAsState() Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Text(text = "Counter: ${uiState.count}") Spacer(modifier = Modifier.height(16.dp)) FloatingActionButton( onClick = { viewModel.increment() }, ) { Icon(imageVector = Icons.Default.Add, contentDescription = "Increment") } } }
疑问
当我使用fun CounterScreen(viewModel: MyViewModel = viewModel())时,重组过程中状态能够被保留;但使用fun CounterScreen(viewModel: MyViewModel = MyViewModel())时,状态却无法保留。然而两种方式看起来都会创建MyViewModel的新实例,请问这是为什么?
解答
这两种方式的核心区别在于ViewModel实例的管理机制:
viewModel()函数并非每次调用都创建新实例:viewModel()是Jetpack Compose提供的专门用于获取ViewModel的工具函数,它会绑定到当前的ViewModelStoreOwner(比如宿主Activity、Fragment或者导航栈条目)。第一次调用时会创建ViewModel实例并存储起来,后续重组或配置变化(如屏幕旋转)时,会直接复用已存储的实例,不会创建新对象,因此状态得以保留。直接调用
MyViewModel()会每次重组都生成新实例:
Compose的重组会根据状态变化多次执行可组合函数的代码逻辑,每次执行到MyViewModel()这一行时,都会创建一个全新的ViewModel实例。旧实例会被丢弃,之前保存的状态自然也就丢失了。
简单来说,viewModel()帮你完成了实例的缓存与生命周期绑定,而直接new的方式完全绕过了这套管理机制,自然无法保留状态。
内容的提问来源于stack exchange,提问作者Turvy
相关产品推荐
相关产品推荐

