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

Jetpack Compose返回后ViewModel技能数据丢失问题求助

问题分析

核心问题是:CharacterSkillScreen销毁后,对应的SkillViewModel会被系统回收,再次进入该页面时会创建全新的ViewModel实例,导致之前添加的技能状态全部丢失。你尝试的rememberSaveable未生效,一是因为没有将保存的状态同步回ViewModel,二是SkillModel未实现序列化接口,无法被rememberSaveable正确持久化。

解决方案

以下是分步修复方案:

1. 让SkillModel实现序列化接口

rememberSaveable要求保存的数据必须可序列化,修改你的SkillModel:

import java.io.Serializable

// 假设SkillModel是data class,添加Serializable接口
data class SkillModel(
    val id: String,
    val title: String,
    val describe: String,
    val firstCarac: String,
    val secondCarac: String,
    val firstParticularity: String,
    val secondParticularity: String
) : Serializable

2. 修复CharacterSkillScreen的状态恢复逻辑

移除冗余的rememberSkillList,直接从ViewModel读取状态,同时在页面初始化时将rememberSaveable保存的列表恢复到ViewModel:

@Composable
fun CharacterSkillScreen(
    arguments: Bundle? = null,
    skillViewModel: SkillViewModel = viewModel()
) {
    // 用rememberSaveable持久化技能列表,确保页面重建/重新进入时能恢复
    val savedSkillList = rememberSaveable {
        mutableStateOf(emptyList<SkillModel>())
    }

    val skillUiState by skillViewModel.uiState.collectAsState()

    // 页面初始化时:如果ViewModel状态为空,从savedSkillList恢复数据
    LaunchedEffect(Unit) {
        if (skillUiState.skillItem.isEmpty() && savedSkillList.value.isNotEmpty()) {
            skillViewModel.restoreSkillItems(savedSkillList.value)
        }
    }

    // ViewModel技能列表变化时,同步保存到savedSkillList
    LaunchedEffect(skillUiState.skillItem) {
        savedSkillList.value = skillUiState.skillItem
    }

    // 剩余UI代码保持不变...
}

同时在SkillViewModel中添加恢复技能的方法:

class SkillViewModel() : ViewModel() {
    // ... 现有代码 ...

    fun restoreSkillItems(items: List<SkillModel>) {
        updateSkillState { it.copy(skillItem = items) }
    }
}

3. 提升ViewModel作用域(更优方案)

如果希望技能状态在整个Character相关流程中持久化(比如CharacterScreen也需要访问),可以将SkillViewModel的作用域提升到父级导航栈,确保返回再进入时复用同一个实例:

// 假设使用Jetpack Navigation,从CharacterScreen的导航栈条目获取ViewModel
@Composable
fun CharacterSkillScreen(
    navController: NavHostController,
    arguments: Bundle? = null,
    // 绑定到CharacterScreen的导航栈,只要CharacterScreen未销毁,ViewModel就会保留状态
    skillViewModel: SkillViewModel = viewModel(navController.getBackStackEntry("character_screen"))
) {
    // ... 剩余代码不变 ...
}

4. 移除ItemSkillView中不必要的ViewModel获取

ItemSkillView无需单独获取ViewModel,直接从上层传递即可,避免潜在的生命周期问题:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ItemSkillView(
    skillModel: SkillModel,
    statsValue: Map<String, Int>,
    skillViewModel: SkillViewModel // 从CharacterSkillScreen传递
) {
    // ... 剩余代码不变 ...
}

在CharacterSkillScreen中调用时传递ViewModel:

skillUiState.skillItem.forEach { skillModel ->
    ItemSkillView(
        skillModel = skillModel,
        statsValue = statsFieldValue,
        skillViewModel = skillViewModel
    )
}
关键说明
  • 默认情况下,ViewModel与页面的LifecycleOwner绑定,页面销毁时ViewModel会被回收,这是状态丢失的核心原因。提升作用域或用rememberSaveable持久化是两种核心解决思路。
  • rememberSaveable仅支持可序列化数据,因此SkillModel必须实现Serializable或Parcelable接口。

内容的提问来源于stack exchange,提问作者Olhm.exe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 11:05:03