Jetpack Compose配置变更或导航时如何保留AndroidView状态
解决方案
问题根因
你当前使用的remember仅能在单次组合生命周期内缓存实例,配置变更(如屏幕旋转、深色模式切换)、导航出栈重建页面时remember缓存会被清空,因此每次重建都会生成新的DataChart实例,导致状态丢失。
可选方案
方案1:ViewModel + Application Context 缓存实例(推荐,适配所有场景)
你之前遇到的内存泄漏问题是因为直接持有Activity Context,改用ApplicationContext创建图表实例即可解决,ApplicationContext是全局单例,和ViewModel生命周期匹配,不会触发泄漏。
代码实现:
// ViewModel中声明图表实例 class ChartViewModel : ViewModel() { var dataChart: DataChart? = null } @Composable fun ChartView(viewModel: ChartViewModel, modifier: Modifier) { val appContext = LocalContext.current.applicationContext // 仅首次组合时初始化实例,后续复用ViewModel中缓存的对象 val chart = remember { viewModel.dataChart ?: DataChart(appContext).also { viewModel.dataChart = it } } AndroidView( modifier = modifier, factory = { chart }, update = { chart -> // 所有需要当前页面Context的操作都在这里执行,不要用初始化时的appContext // 你的图表更新逻辑 } ) } // 如果是Navigation Compose场景,从当前导航回栈条目获取ViewModel,保证回栈条目销毁时才释放实例 @Composable fun ChartRoute(navController: NavController) { val backStackEntry = LocalNavBackStackEntry.current val viewModel: ChartViewModel = viewModel(backStackEntry) ChartView(viewModel = viewModel, modifier = Modifier.fillMaxSize()) }
如果图表依赖Activity主题,可使用ContextThemeWrapper包裹ApplicationContext:
DataChart(ContextThemeWrapper(appContext, R.style.YourActivityTheme))
方案2:自定义Saver配合rememberSaveable(仅适配配置变更场景)
如果不需要跨导航保留状态,仅需要解决配置变更导致的实例重建,可以用自定义Saver的rememberSaveable缓存实例,不需要改动ViewModel:
// 自定义Saver,同进程内直接保留实例引用 val ChartSaver = Saver<DataChart, DataChart>( save = { it }, restore = { it } ) @Composable fun ChartView(modifier: Modifier) { val context = LocalContext.current val chart = rememberSaveable(saver = ChartSaver) { DataChart(context) } AndroidView( modifier = modifier, factory = { chart }, update = { /* 更新逻辑 */ } ) }
注意:该方案仅适用配置变更场景,页面被导航弹出后再返回时实例还是会重建。
注意事项
- 如果图表有需要调用宿主Context的操作(如获取窗口尺寸、弹Toast),统一在
update回调中用传入的chart.context执行,不要用初始化时的ApplicationContext。 - 页面永久销毁时如果图表有资源需要释放,可通过
DisposableEffect监听生命周期手动释放:
DisposableEffect(Unit) { onDispose { // 可选:如果页面永久销毁不需要保留实例,可在这里释放资源并清空ViewModel中的引用 viewModel.dataChart?.release() viewModel.dataChart = null } }
内容的提问来源于stack exchange,提问作者mike_t
相关产品推荐
相关产品推荐

