Jetpack Compose+Navigation旋转屏幕后数据丢失问题求助
使用Jetpack Compose结合Navigation框架开发应用时,旋转屏幕后所有数据都会重置。每次旋转都会触发Activity的onCreate方法,重新创建NavHost与ViewModel,原本以为应用状态会自动处理该问题。

启动Activity代码
class NavActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MyAppTheme() { MyAppApp() } } } }
包含NavHost的Composable代码
@Composable fun MyAppApp( appState: MyAppAppState = rememberAppState() ) { NavHost( navController = appState.navController, startDestination = Screen.ProductAddPath.route ) { composable(Screen.ProductAddPath.route) { ProductEditView( vm = ProductEditViewModel (appState.context) ) } } }
ViewModel代码
class ProductEditViewModel(context: Context) : ViewModel() { private val _productName = MutableStateFlow("qsd") val productName = _productName.asStateFlow() fun onProductNameChange(it: String) { _productName.value = it } }
View代码
@Composable fun ProductEditView(vm: ProductEditViewModel) { Surface( color = MaterialTheme.colorScheme.background) { val message by vm.productName.collectAsState() Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth() ) { OutlinedTextField( value = message, onValueChange = { vm.onProductNameChange(it) }, ) } } }
问题原因及修复方案
核心问题
你直接手动实例化ProductEditViewModel,这种方式会在每次Composable重组(包括屏幕旋转)时创建全新的ViewModel实例,导致之前的状态完全丢失。ViewModel的核心作用就是在配置变更时保留状态,必须依赖Jetpack的ViewModel生命周期管理机制才能生效。
修复步骤
- 替换手动创建ViewModel的方式
在Composable中使用viewModel()函数获取ViewModel实例,该函数会自动将ViewModel与当前NavBackStackEntry的生命周期绑定,配置变更时不会重建实例:
@Composable fun MyAppApp( appState: MyAppAppState = rememberAppState() ) { NavHost( navController = appState.navController, startDestination = Screen.ProductAddPath.route ) { composable(Screen.ProductAddPath.route) { // 使用viewModel()自动管理生命周期 val vm: ProductEditViewModel = viewModel() ProductEditView(vm = vm) } } }
- 调整ViewModel的构造逻辑
如果必须使用Context,不要直接传入普通Context,改用AndroidViewModel获取Application级别的上下文(避免内存泄漏):
class ProductEditViewModel(application: Application) : AndroidViewModel(application) { private val context = application.applicationContext private val _productName = MutableStateFlow("qsd") val productName = _productName.asStateFlow() fun onProductNameChange(it: String) { _productName.value = it } }
如果不需要Context,直接简化ViewModel:
class ProductEditViewModel : ViewModel() { private val _productName = MutableStateFlow("qsd") val productName = _productName.asStateFlow() fun onProductNameChange(it: String) { _productName.value = it } }
补充说明
viewModel()函数会确保ViewModel在当前导航页面存在期间保留,只有当导航离开该页面时才会被销毁。- 若使用Hilt等依赖注入框架,可替换为
hiltViewModel()函数,同样遵循生命周期管理规则。
内容的提问来源于stack exchange,提问作者oursgris
相关产品推荐
相关产品推荐

