You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose+Navigation旋转屏幕后数据丢失问题求助

旋转屏幕后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生命周期管理机制才能生效。

修复步骤

  1. 替换手动创建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)
            }
        }
}
  1. 调整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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 19:00:31