在多个膨胀的EditTexts上设置文本会导致在旋转后使用相同的文本填充所有文本

时间:2014-04-02 00:52:11

标签: android android-layout android-edittext layout-inflater screen-rotation

我正在夸大一些EditTexts并将其添加到LinearLayout

private void setupCommentViews(){
    int i = 0;
        Iterator<CommentInformation> iterator = commentInformations.iterator();
    while(iterator.hasNext()) {
            i++;
            View v = LayoutInflater.from(context).inflate(R.layout.comment_row_item, commentsContainer, false);

            EditText commentField = (EditText)v.findViewById(R.id.comment);         

            CommentInformation commentInformation = iterator.next();
            final String uniqueId = commentInformation.getUniqueId();

            String currentCommentText = comments.get(uniqueId);         
            if(currentCommentText != null) {
                Log.v("into","Setting old text: "+currentCommentText);
                commentField.setText(currentCommentText);
            } else {
                Log.v("into","Setting empty text: "+i);
                commentField.setText("Setting empty text: "+i);
            }


            commentField.addTextChangedListener(new TextWatcher() {

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                }

                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {

                }

                @Override
                public void afterTextChanged(Editable s) {
                    comments.put(uniqueId, s.toString().trim());
                }
            });

            commentsContainer.addView(v);
        }
}

首次运行后的日志如下所示:

04-01 17:40:41.244: V/into(28770): Setting empty text: 1
04-01 17:40:41.254: V/into(28770): Setting empty text: 2
04-01 17:40:41.254: V/into(28770): Setting empty text: 3

所有EditTexts中都包含正确的文本(“设置空文本:#”)

-

我正在向我TextChangedListener添加EditText我膨胀的内容,当文本发生变化时,我更新Map<String, String>并将uniqueId作为键,将注释文本作为值

更改其中一条评论后旋转手机时出现问题。我将评论Map保存在onSaveInstanceState

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putSerializable(COMMENTS, (Serializable)comments);
}

然后我在onActivityCreated

中检索它们
if(savedInstanceState != null) {
        Log.v("into","Retrieving...");
        comments = (Map<String, String>)savedInstanceState.getSerializable(COMMENTS);
}

我还遍历Map并验证是否有一个条目包含正确的uniqueId和正确更改的注释文本。

-

接下来,我再次致电setupCommentViews()。这次日志看起来是正确的,但是EditTexts ALL与最后一个(最后一个膨胀的文本)具有相同的文本。

04-01 17:42:49.664: V/into(28770): Setting empty text: 1
04-01 17:42:49.664: V/into(28770): Setting old text: Changed the second textview
04-01 17:42:49.674: V/into(28770): Setting empty text: 3

但所有EditTexts现在都说:“设置空文本:3”

使用ListView并非我正在寻找的解决方案,因为EditTexts内有ListView的{​​{1}}带有AdjustResize softInputMode < / p>

-

任何人都可以了解这里发生的事情吗?

4 个答案:

答案 0 :(得分:14)

默认情况下,当调用活动的onSaveInstanceState方法时,它也会通过视图层次结构并尽可能保存任何视图的状态,并在onRestoreInstanceState方法时恢复这些视图状态活动稍后调用。当调用每个View来保存状态时,我们可以在View类中看到这个方法:

protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
        if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
            mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
            Parcelable state = onSaveInstanceState();
            if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
                throw new IllegalStateException(
                        "Derived class did not call super.onSaveInstanceState()");
            }
            if (state != null) {
                // Log.i("View", "Freezing #" + Integer.toHexString(mID)
                // + ": " + state);
                container.put(mID, state);
            }
        }
    }

EditText继承自TextView,当检查TextView的代码时,我们看到onSaveInstanceState方法返回当前文本,onRestoreInstanceState方法返回文本并显示。

现在,回到你的代码。您自己保存文本内容并在调用onCreate时恢复它,但EditText本身也保存文本并在调用Activity的onRestoreInstanceState方法时恢复,这在onCreate之后调用还有一件事,你的所有EditText都有相同的id,所以当视图层次结构被保存到SparseArray时,最后一个EditText状态(在这种情况下是文本内容)将覆盖所有以前的状态。这就是你的问题发生的原因。

<强>解决方案:

  1. 您可以覆盖活动的方法onRestoreInstanceState,而不是调用超级方法,这样您就可以阻止视图自动恢复其状态,但我不认为这是个好主意,因为可能还有其他方法默认情况下需要恢复的东西,不仅仅是你的EditText
  2. 您可以将EditText的属性saveEnabled设置为false,以便它不会自行恢复状态,我建议这样做。

答案 1 :(得分:1)

EditText根据resId恢复文本。如果您的edittexts没有resIds或者所有人都有相同的resIds,那么您将有恢复问题。

答案 2 :(得分:1)

我遇到了同样的问题。 在我的自定义LinearLayout中,我覆盖了这些方法。

   @Override
protected Parcelable onSaveInstanceState() {
    Parcelable superState = super.onSaveInstanceState();
    return new SavedState(superState, txtData.getText().toString());
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
    SavedState savedState = (SavedState) state;
    super.onRestoreInstanceState(savedState.getSuperState());
    txtData.setText(savedState.data);
}

@Override
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
    super.dispatchFreezeSelfOnly(container);
}

@Override
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
    super.dispatchThawSelfOnly(container);
}

private class SavedState extends BaseSavedState {
    public final Creator<SavedState> CREATOR = new Creator<SavedState>() {
        @Override
        public SavedState createFromParcel(Parcel in) {
            return new SavedState(in);
        }

        @Override
        public SavedState[] newArray(int size) {
            return new SavedState[size];
        }
    };
    private String data;

    public SavedState(Parcel source) {
        super(source);
        data = source.readString();
    }

    public SavedState(Parcelable superState, String data) {
        super(superState);
        this.data = data;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeString(data);
    }
}

希望这有帮助。

答案 3 :(得分:0)

我也遇到了这个问题,但是我必须先恢复状态。因此,我创建了一个名为FixedEditText的视图,并同时覆盖了dispatchSaveInstanceState()dispatchRestoreInstanceState()两种方法。就像这样:

 override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) {
    try {
        val key = initKey()
        if (key != null && isSaveEnabled) {
            val state = onSaveInstanceState()
            if (state != null) {
                //don't use the id as the key
                container.put(key.hashCode(), state)
            }
        }
    } catch (e: Exception) {
        super.dispatchSaveInstanceState(container)
        e.printStackTrace()
    }
}

override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) {
    try {
        val key = initKey()
        if (key != null) {
            val state = container.get(key.hashCode())
            if (state != null) {
                onRestoreInstanceState(state)
            }
        }
    } catch (e: Exception) {
        super.dispatchRestoreInstanceState(container)
        e.printStackTrace()
    }
}
 private fun initKey(): Any? {
    (parent as? View)?.run {
        //My ViewGroup has diff id.
        return "${this.javaClass.simpleName}$${this.id}"
    }
    return null
}