【问题标题】:Setting text on multiple inflated EditTexts causes all to be populated with same text after rotation在多个膨胀的 EditTexts 上设置文本会导致旋转后全部填充相同的文本
【发布时间】: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&lt;String, String&gt;,并将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 的位置插入调试断点并找出答案。

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


【解决方案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 状态(在这种情况下是文本内容)将覆盖所有以前的状态。这就是你的问题发生的原因。

解决方案:

  1. 您可以覆盖活动的方法onRestoreInstanceState 而不是调用超级方法,这样您就可以防止视图自动恢复其状态,但我认为这不是一个好主意,因为可能需要做其他事情默认恢复,不仅是你的 EditText
  2. 可以将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
      }
      

      【讨论】:

        猜你喜欢
        • 2023-03-24
        • 1970-01-01
        • 2020-03-04
        • 2016-09-29
        • 1970-01-01
        • 2013-02-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多