我有一个包含LinearLayout的Fragment,其中不同的项目根据某些业务逻辑而膨胀。这些项目中包含EditText。当我有多个具有不同内容的这些项目并且我分离/附加片段时,所有EditTexts以某种方式获得所有相同的文本。只要EditText在布局文件中有id,就会发生这种情况。
为什么会这样?除了删除id之外还有其他方法可以防止这种情况吗?我想在我的虚增项目上使用findViewById
来访问视图,而不是容易出错getChildAt
。
我已经创建了一个简约示例来演示https://github.com/rodja/EditTextValueProblem
中的问题答案 0 :(得分:26)
可以通过在EditTexts布局定义中设置android:saveEnabled="false"
来简单地修复它。当然,您需要确保自己保存/恢复内容。所以这是一个非直观的工作 - 但它适用于我的情况。尽管如此,整个事情看起来像是一个Android错误:
Android布局系统的一个很好的功能是
在整个树[...]
中,ID不一定是唯一的
如Android documentation中所述。这使得代码和布局重用变得更加简单,并且被开发人员大量使用。我认为视图的保存/恢复实例状态实现使用视图的ID作为存储其状态的键,因此它依赖于整个树中的唯一性。 WTF?
<强>更新强>
我已将ListView
添加到the example at GitHub,这表明ListView
几乎肯定会使用类似的解决方法来阻止EditTexts遇到此问题。可以看出,输入到ListView内的EditText的文本不会自动恢复。
答案 1 :(得分:8)
有一种不同的可能性,只需更改编辑文本的ID,例如
mEditText.setId((parentView.getId()+editTextPosition+someFinalNumber));
或者如果它是某个自定义布局中的EditText:
mEditText.setId((this.getId()+someFinalNumber));
通过这种方式,所有EditTexts都将具有不同的ID,并且文本将被正确恢复。
答案 2 :(得分:0)
来自未来的问候。可悲的是,Android框架开发人员仍然喜欢嘲笑我们。感谢我们聪明的科学家,我们提出了更好的解决方案。参见下文(是的,我们将来仍会使用Java)。您可以找到原始的“研究论文” here。
private static final String KEY_SUPER = "superState";
private static final String KEY_CHILD = "childState";
@Override
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
// Don't call super, to disable saving child view states
dispatchFreezeSelfOnly(container);
}
@Override
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
// Similar as above, but other way around
dispatchThawSelfOnly(container);
}
@Override
protected @Nullable Parcelable onSaveInstanceState() {
val bundle = new Bundle();
val superState = super.onSaveInstanceState();
bundle.putParcelable(KEY_SUPER, superState);
val childStates = saveChildViewStates();
bundle.putSparseParcelableArray(KEY_CHILD, childStates);
return bundle;
}
private SparseArray<Parcelable> saveChildViewStates() {
val childViewStates = new SparseArray<Parcelable>();
for(val view : getChildViews())
view.saveHierarchyState(childViewStates);
return childViewStates;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
val bundle = (Bundle) state;
val superState = bundle.getParcelable(KEY_SUPER);
super.onRestoreInstanceState(superState);
val childState = bundle.getSparseParcelableArray(KEY_CHILD);
restoreChildViewStates(childState);
}
private void restoreChildViewStates(SparseArray<Parcelable> states) {
for(val view : getChildViews())
view.restoreHierarchyState(states);
}
private Iterable<View> getChildViews() {
int childCount = getChildCount();
return () -> new Iterator<View>() {
private int index = 0;
@Override
public boolean hasNext() {
return index < childCount;
}
@Override
public View next() {
val view = getChildAt(index);
if(view == null) {
throw new RuntimeException("View was null. Index: " + index +
" count: " + childCount + ".");
}
Objects.requireNonNull(view);
index++;
return view;
}
};
}
PS:请注意,如果您更改子View
的顺序,则此解决方案可能无法正常运行。鲍勃的叔叔说我们现在需要的东西还可以。我把它留给未来的科学家在此基础上进行。
PPS:如果您在Google工作,请随时将其粘贴粘贴到框架中并在其上构建。
PPPS:您可能想使用更好的应用程序架构,例如MVVM。