Почему Android изменяет значение EditTexts с тем же идентификатором?
У меня есть фрагмент, содержащий LinearLayout, где разные элементы раздуваются в зависимости от некоторой бизнес-логики. В этих элементах содержится EditText. Когда у меня есть несколько элементов с различным контентом, и я отсоединяю/прикрепляю фрагмент, все EditTexts каким-то образом получают одинаковый текст. Это происходит только до тех пор, пока EditText имеет идентификатор в файле макета.
Почему это происходит? Есть ли другой способ предотвратить это, кроме удаления идентификатора? Я хотел бы использовать findViewById
на моих раздутых элементах для доступа к представлениям, а не к ошибкам getChildAt
.
Я создал минималистский пример, чтобы продемонстрировать проблему на https://github.com/rodja/EditTextValueProblem
Ответы
Ответ 1
Его можно просто зафиксировать, установив android:saveEnabled="false"
в определении макета EditTexts. Конечно, вам нужно убедиться, что содержимое сохранено/восстановлено самостоятельно. Так что это неинтуитивная работа - но это работает для моего дела. Тем не менее, все это выглядит как ошибка Android:
Хорошей особенностью системы макета Android является то, что
Идентификатор не должен быть уникальным во всем дереве [...]
как указано в документации для Android. Это значительно упрощает использование кода и компоновки и в значительной степени используется разработчиками. Я думаю, что реализация состояния экземпляра save/restore для представлений использует идентификатор представления как ключ для сохранения состояния, поэтому он полагается на уникальность в целом дерева. WTF?
Обновление
Я добавил пример ListView
в в GitHub, который демонстрирует, что ListView
почти наверняка использует аналогичное обходное решение для предотвращения использования EditTexts в этой проблеме, Как видно, текст, который вводится в EditText внутри ListView, не восстанавливается автоматически.
Ответ 2
Существует другая возможность, просто измените идентификатор текста редактирования, например,
mEditText.setId((parentView.getId()+editTextPosition+someFinalNumber));
Или, если это EditText внутри некоторого настраиваемого макета:
mEditText.setId((this.getId()+someFinalNumber));
Таким образом, все EditTexts будут иметь другой идентификатор, и текст будет восстановлен правильно.
Ответ 3
Я думаю, это связано с тем, что состояние всех EditTexts с идентификатором автоматически сохраняется. Если вы выполните FragmentTransactions или измените ориентацию, активность будет воссоздана, и состояние EditTexts будет восстановлено, так как все они имеют одинаковый идентификатор, все они получат одинаковое значение. Мое первое предложение будет переопределять методы onRestoreInstanceState и onSaveInstanceState вашей деятельности, например:
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
// super.onRestoreInstanceState(savedInstanceState); <-- Make sure this is at least commented out or deleted altogether
}
@Override
protected void onSaveInstanceState(Bundle outState) {
// super.onSaveInstanceState(outState); <-- Make sure this is at least commented out or deleted altogether
}
Если методы в суперклассе не вызываются, он должен прекратить автоматическое сохранение и восстановление состояний. Дайте мне знать, если это сработает, я не могу проверить это прямо сейчас. Если это не сработает, я уверен, что мы можем найти другую работу.
В любом случае у вас есть проблемы с вашими руками, с которыми не так много приходится иметь дело, использует ListView вместо опции LinearLayout no? Потому что я уверен, что использование ListView также решит проблему.