Дублированный текст во всех EditTexts после OnRetainCustomConfigurationInstance - PullRequest
0 голосов
/ 11 октября 2018

Когда я использую onRetainCustomNonConfigurationInstance для сохранения текста, содержащегося в моих пользовательских EditTexts, после вращения устройства текст, содержащийся в последнем EditText, дублируется для всех остальных в целевом макете.

При отладке с точками остановаЯ обнаружил, что все текстовые значения верны до конца.Но после того, как изменения сделаны, все EditTexts получают одинаковый текст (текст из последнего), и основное внимание уделяется первому в макете.

Я повторил это поведение в простейшем проектеЯ мог бы.Я пытался использовать оба уровня Android API 24 и 28.

Откуда возникает это поведение и как его исправить?

MainActivity.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>

CustomEdit.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();
    }
}

custom_edit_text.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>

CustomSave.java:

public class CustomSave {
    public ArrayList<String> texts;

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

Спасибо.

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

Так что здесь происходит то, что Android также обрабатывает сохранение состояния для вашей пользовательской реализации EditText, которая перезаписывает вашу.Поскольку ваш список CustomEdit экземпляров генерируется динамически, вам, скорее всего, не нужно полагаться на Android для сохранения состояния ваших представлений, поскольку они не имеют уникальных идентификаторов.

Поскольку ваш CustomEdit раздувает custom_edit_text.xml (который объявляет EditText ID как @+id/edit), это означает, что каждый CustomEdit, который вы добавляете в макет, имеет одинаковый идентификатор для внутреннего EditText- R.id.edit.Поскольку все они имеют одинаковые идентификаторы, каждое представление будет сохранять свое состояние в этом идентификаторе, поэтому последним, сохраняющим свое состояние, в конечном итоге будет текст, примененный ко всем представлениям при восстановлении состояния.

Есть две вещи, которые вы можете сделать, чтобы избежать этого:

  1. В вашем custom_edit_text.xml добавьте android:saveEnabled="false" к EditText.Это предотвратит сохранение состояния View.Это было бы предпочтительным, так как это позволяет избежать ненужной работы.

  2. Выполните восстановление состояния в onRestoreInstanceState(), где состояние представления восстанавливается в настоящее время.

0 голосов
/ 11 октября 2018

Для решения этой проблемы есть два варианта: переместить код в другую точку жизненного цикла действия или изменить определение xml для CustomEdit.

жизненный цикл 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 не работает, заключается в том, что он основан на атрибуте android:id каждого представления, иВаши EditText теги имеют одинаковый идентификатор.Это означает, что все четыре значения сохраняются с одним и тем же ключом, поэтому последнее значение перезаписывает все предыдущие значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...