You need to enable JavaScript to run this app. Jetpack Compose配置变更或导航时如何保留AndroidView状态
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 08:06:06