带有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找到了导致它的原因!感谢您指出碎片创作,深入研究,我找到了罪魁祸首。看看答案。