在多个膨胀的 EditTexts 上设置文本会导致旋转后全部填充相同的文本
Posted
技术标签:
【中文标题】在多个膨胀的 EditTexts 上设置文本会导致旋转后全部填充相同的文本【英文标题】:Setting text on multiple inflated EditTexts causes all to be populated with same text after rotation 【发布时间】:2014-05-13 00:52:58 【问题描述】:我正在夸大一些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
并且所有的 EditText 中都有正确的文本(“设置空文本:#”)
-
我正在向我的EditText
添加一个TextChangedListener
,然后我会在更改文本时更新Map<String, String>
,并将uniqueId 作为键,将注释文本作为值。
在更换其中一个 cmets 后旋转手机时会出现问题。我将 cmets 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
不是我正在寻找的解决方案,因为ListView
内部有很多带有EditTexts
的错误AdjustResize
softInputMode
-
谁能解释这里发生了什么?
【问题讨论】:
我收集到您的每个 EditText 组件都有自己的唯一 ID。如果是这样,并且由于您将 ID 保存到地图中,您不能只遍历地图,获取唯一 ID,将其与您的每个 EditText 匹配,然后将结果(即setText
)写入每个 EditText 吗?
每个EditText
都有相同的ID (R.id.comment)。由于我们分别对它们进行充气,我认为这没关系,因为我们使用新充气的View
v (v.findViewById(R.id.comment))
获得对它们的引用
即使您单独对它们进行膨胀,当您执行 setText
时,android 也会存储为该 ID 设置的值,因此无论是最后设置的值,它都会显示给您的所有 EditText相同的 ID。
嗯,我不确定,因为第一遍不会导致所有EditTexts
都将“设置空文本:3”作为值吗?而是第一次正确地具有“设置空文本:1”“设置空文本:2”和“设置空文本:3”
在您设置 EditText 的位置插入调试断点并找出答案。
【参考方案1】:
默认情况下,当调用一个activity的onSaveInstanceState
方法时,它也会遍历视图层次结构,如果可能的话,尝试保存任何视图的状态,如果稍后调用activity的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 状态(在这种情况下是文本内容)将覆盖所有以前的状态。这就是你的问题发生的原因。
解决方案:
-
您可以覆盖活动的方法
onRestoreInstanceState
而不是调用超级方法,这样您就可以防止视图自动恢复其状态,但我认为这不是一个好主意,因为可能需要做其他事情默认恢复,不仅是你的 EditText
可以将EditText的saveEnabled属性设置为false,这样就不会自己恢复状态了,我推荐这个。
【讨论】:
非常感谢。 android:saveEnabled="false" 做得很好。【参考方案2】:我遇到了同样的问题。 在我的自定义 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】:EditText 根据 resId 恢复文本。如果您的编辑文本没有 resId 或都具有相同的 resId,您将遇到恢复问题。
【讨论】:
【参考方案4】:我也遇到了这个问题,但是我必须恢复之前的状态。所以我创建了一个名为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
【讨论】:
以上是关于在多个膨胀的 EditTexts 上设置文本会导致旋转后全部填充相同的文本的主要内容,如果未能解决你的问题,请参考以下文章
为 UITextView 设置文本会导致重置为默认字体和颜色问题
我将视图膨胀了 5 次,膨胀的视图有一个 EditText,现在我在屏幕上有 5 个 EditText,如何从这些 EditTexts 中获取文本
在 recyclerview 上退出文本会导致焦点问题并修复它会破坏键盘隐藏 EditText 可见性