java - OnRetainCustomConfigurationInstance 之后所有编辑文本中的重复文本

标签 java android android-edittext rotation

当我使用 onRetainCustomNonConfigurationInstance 保存我的自定义 EditText 中包含的文本时,在我旋转设备后,最后一个 EditText 中包含的文本被复制到目标布局中的所有其他文本。

在断点调试的时候,发现所有的文本值一路都是正确的。但是在更改完成后,所有 EditText 都会显示相同的文本(最后一个的文本),并且焦点会转到布局中的第一个。

我在尽可能简单的项目中复制了这种行为。我尝试了 android API 级别 24 和 28。

这种行为从何而来,我该如何解决?

主要 Activity .java :

public class MainActivity extends AppCompatActivity {
    private ArrayList<CustomEdit> editList=new ArrayList<CustomEdit>();
    private LinearLayout layout;
    private Button addButton;

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        addButton=findViewById(R.id.add_button);
        layout = findViewById(R.id.layout);

        addButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                addEdit();
            }
        });
        CustomSave data = (CustomSave)getLastCustomNonConfigurationInstance();
        if(data==null) return;

        for(int i = 0; i<data.texts.size();i++){
            addEdit(data.texts.get(i));
        }
    }
    @Override
    public Object onRetainCustomNonConfigurationInstance() {
        CustomSave data = save();
        return data;}

    private CustomSave save(){
        ArrayList<String> texts = new ArrayList<String>();
        for(int i =0; i<editList.size(); i++)
            texts.add(editList.get(i).getText());
        return new CustomSave(texts);}

    /**
     * Create a new custom EditText with hint
     */
    private void addEdit(){
        CustomEdit newEdit = new CustomEdit(this,editList.size());
        layout.addView(newEdit,editList.size());
        editList.add(newEdit);}
    /**
     * Create a new custom editText with text
     * @param text
     */
    private void addEdit(String text){
        CustomEdit newEdit;
        if(text==null) newEdit = new CustomEdit(this, editList.size());
        else  newEdit = new CustomEdit(this, editList.size(),text);
        layout.addView(newEdit,editList.size());
        editList.add(newEdit);}
}

activity_main.xml :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:text="Title"
        android:gravity ="center"/>
    <HorizontalScrollView
        android:id="@+id/scroll1"
        android:layout_below="@id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingStart="10dp"
        android:paddingLeft="10dp">
        <LinearLayout
            android:id="@+id/layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <Button
                android:id="@+id/add_button"
                android:layout_width="100dp"
                android:layout_height="wrap_content"
                android:text="+"/>
        </LinearLayout>
    </HorizontalScrollView>
</RelativeLayout>

自定义编辑器.java :

public class CustomEdit extends RelativeLayout {
    private EditText editText;
    private Button closeButton;
    private int indexNumber;

    public CustomEdit(Context context, int indexNumber) {
        super(context);
        this.indexNumber =indexNumber;
        init();
    }
    public CustomEdit(Context context, int indexNumber, String text){
        super(context);
        this.indexNumber=indexNumber;
        init();
        editText.setText(text);
    }
    public CustomEdit(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    public CustomEdit(Context context, AttributeSet attrs, int defStyleAttr){
        super(context, attrs, defStyleAttr);
        init();
    }
    private void init(){
        inflate(getContext(),R.layout.custom_edit_text,this);

        editText = (EditText)findViewById(R.id.edit);
        editText.setHint("EditText "+(indexNumber+1));

        closeButton = (Button)findViewById(R.id.close_button);
        closeButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                ((MainActivity)getContext()).closeEdit(indexNumber);
            }
        });
    }
    public String getText(){
        return editText.getText().toString();
    }
}

自定义编辑文本.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="100dp"
    android:layout_height="40dp">
    <EditText
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/edit"
        android:inputType="text"
        android:hint="Element"
        android:maxLength="30"/>
    <Button
        android:id="@+id/close_button"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_alignRight="@id/edit"
        android:layout_alignEnd="@id/edit"
        android:layout_alignTop="@id/edit"
        android:text="X"/>
</RelativeLayout>

自定义保存.java :

public class CustomSave {
    public ArrayList<String> texts;

    CustomSave(ArrayList<String> texts){
        this.texts = texts;
    }
}

谢谢。

最佳答案

对于如何解决这个问题,您有两种选择:将您的代码移动到 Activity 生命周期中的不同点或更改 CustomEdit 的 xml 定义| .

Android 生命周期

将此代码移出 onCreate() :

CustomSave data = (CustomSave)getLastCustomNonConfigurationInstance();
if(data==null) return;

for(int i = 0; i<data.texts.size();i++){
    addEdit(data.texts.get(i));
}

并将其放入onRestoreInstanceState()相反:

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);

    CustomSave data = (CustomSave)getLastCustomNonConfigurationInstance();
    if(data==null) return;

    for(int i = 0; i<data.texts.size();i++){
        addEdit(data.texts.get(i));
    }
}

XML 定义

将此属性添加到 <EditText>在你的 custom_edit_text.xml 中标记文件:

android:saveEnabled="false"

您为保存/恢复文本值而编写的代码没有任何问题。但是,之后 onCreate() ,Android 会自动执行其自己的 保存/恢复逻辑,这会覆盖您所做的。

如果您从 onCreate() 移动您的代码至 onRestoreInstanceState() ,那么您的代码将在 Android 的自动保存/恢复后运行,因此您将“获胜”。或者,您可以通过添加 saveEnabled=false 来禁用自动保存/恢复属性。

Android 的自动保存/恢复不起作用的原因是它基于每个 View 的 android:id。属性,还有你的 EditText标签都具有相同的 ID。这意味着所有四个值都使用相同的键保存,因此最后一个值会覆盖所有以前的值。

关于java - OnRetainCustomConfigurationInstance 之后所有编辑文本中的重复文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52762930/

相关文章:

java - 在拖动 JSplitPane 分隔线时如何避免(或消耗)鼠标事件?

java - Android(Java)网络编程资源

android - 从 Android SQLite 数据库中删除动态创建的 EditText

android - 重复调用 LineBackgroundSpan drawBackground()

java - 如何更正平滑移动谷歌地图 v2 中的标记?

java - getText 与 onTextChanged charSequence

java - 如何为 HtmlUnit 中没有 value 属性的文本字段提供值?

java - 扩展通用类的原始类型警告

java - 使用 Docker api 连接到容器后如何使用 stdin、stdout 和 stderr 流?

android - 确定android中连接的蓝牙设备的类型