为什么Android会使用相同的ID更改EditTexts的值?

时间:2013-12-05 16:36:31

标签: android view android-fragments android-edittext

我有一个包含LinearLayout的Fragment,其中不同的项目根据某些业务逻辑而膨胀。这些项目中包含EditText。当我有多个具有不同内容的这些项目并且我分离/附加片段时,所有EditTexts以某种方式获得所有相同的文本。只要EditText在布局文件中有id,就会发生这种情况。

为什么会这样?除了删除id之外还有其他方法可以防止这种情况吗?我想在我的虚增项目上使用findViewById来访问视图,而不是容易出错getChildAt

我已经创建了一个简约示例来演示https://github.com/rodja/EditTextValueProblem

中的问题

3 个答案:

答案 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。