带有SavedState的Android ViewModel重写新实例的参数

带有SavedState的Android ViewModel重写新实例的参数,android,android-fragments,android-lifecycle,android-savedstate,viewmodel-savedstate,Android,Android Fragments,Android Lifecycle,Android Savedstate,Viewmodel Savedstate,我有一个应用程序,它具有主/细节类型的架构。当我选择某个项目时,详细信息显示在详细信息片段中 对于要知道要加载什么的细节片段,id通过参数发送过来。在VM中使用SavedStateHandle,我可以直接从句柄读取这些参数,而无需在Fragment本身中重新路由。这对于第一个细节片段非常有效。问题在于接下来的选择 每次我加载详细信息时,都会填充来自第一个选择的id,尽管每次创建新片段时都会同时创建新视图模型 我在查看lifecycle viewmodel savedstate库(v.2.3.1)

我有一个应用程序,它具有主/细节类型的架构。当我选择某个项目时,详细信息显示在详细信息片段中

对于要知道要加载什么的细节片段,
id
通过
参数发送过来。在VM中使用
SavedStateHandle
,我可以直接从句柄读取这些参数,而无需在
Fragment
本身中重新路由。这对于第一个细节片段非常有效。问题在于接下来的选择

每次我加载详细信息时,都会填充来自第一个选择的
id
,尽管每次创建新片段时都会同时创建新视图模型

我在查看lifecycle viewmodel savedstate库(v.2.3.1)的代码时,在
SavedStateHandle
中找到了此方法,称为:

static SavedStateHandle createHandle(@Nullable Bundle restoredState,
        @Nullable Bundle defaultState) {
    if (restoredState == null && defaultState == null) {
        return new SavedStateHandle();
    }

    Map<String, Object> state = new HashMap<>();
    if (defaultState != null) {
        for (String key : defaultState.keySet()) {
            state.put(key, defaultState.get(key));
        }
    }

    if (restoredState == null) {
        return new SavedStateHandle(state);
    }

    ArrayList keys = restoredState.getParcelableArrayList(KEYS);
    ArrayList values = restoredState.getParcelableArrayList(VALUES);
    if (keys == null || values == null || keys.size() != values.size()) {
        throw new IllegalStateException("Invalid bundle passed as restored state");
    }
    for (int i = 0; i < keys.size(); i++) {
        state.put((String) keys.get(i), values.get(i));
    }
    return new SavedStateHandle(state);
}
static savedstateholder createHandle(@Nullable Bundle restoredState,
@可为空的包(默认状态){
if(restoredState==null&&defaultState==null){
返回新的SavedStateHandle();
}
映射状态=新的HashMap();
if(defaultState!=null){
for(字符串键:defaultState.keySet()){
state.put(key,defaultState.get(key));
}
}
if(restoredState==null){
返回新的SavedStateHandle(状态);
}
ArrayList keys=restoredState.getParcelableArrayList(keys);
ArrayList值=restoredState.getParcelableArrayList(值);
if(keys==null | | values==null | | keys.size()!=values.size()){
抛出新的IllegalStateException(“作为还原状态传递的无效包”);
}
对于(int i=0;i
在这里我可以看到,在
defaultState
中,为每个新视图模型设置了正确的id。但正如您所看到的,
defaultState
首先处理,然后再处理
restoredState
restoredState
包含与旧
id
相同的密钥,该密钥最后替换了
defaultState
中的正确密钥

我可以理解,这可能是真正恢复所需要的行为,但在我的情况下,我不会恢复片段。是的,这个类是相同的,但我只是用另一个细节片段替换细节片段,其中包含新的/不同的数据


我做错什么了吗?我可以给框架一个提示,这不是恢复,我对从旧片段保存的值不感兴趣吗?

我没有提到的是,我正在使用
ViewPager2
进行主/详细视图。我不认为它对州的摊位有影响,但它有。

ViewPager2
库正在后台保存和恢复状态,然后由
SavedStateHandle
使用。要使用状态映射片段,它使用
FragmentStateAdapter
中的ID。我没有重写
getItemId
方法,所以ID是按位置分配的


这当然会将相同的状态映射到新片段的确切位置。实现将不同ID分配给片段的不同实例的
getItemId
解决了这个问题。

如果您创建一个全新片段并因此获得一个新的ViewModel,那么
restoredState
将为空。什么使你认为它不是空的?调试?我可以看出它不是空的。另外,根据定义,saveInstanceState应该在实例之间保存状态,所以我并不感到惊讶。但在这种情况下,这并不是真正想要的行为。一个全新的片段和一个ViewModel关联的工作一个全新的片段没有保存状态。请包括您是如何创建全新片段的,以及您是如何创建ViewModelOk找到了导致它的原因!感谢您指出碎片创作,深入研究,我找到了罪魁祸首。看看答案。