Использование onRetainCustomNonConfigurationInstance для сохранения данных при изменении конфигурации

Я некоторое время программировал для Android и все еще ищу решения для сохранения данных при изменении конфигурации. Помимо сохранения Parcelables в Activity Bundle в документах onSaveInstanceState предлагается использовать Fragment с флагом setRetainInstance, установленным в true.

Но я только что наткнулся на код, который использует onRetainCustomNonConfigurationInstance для хранения произвольных объектов (причудливым образом, но по существу больших объектов без ссылок на Activity и т. д.). Я никогда не видел, чтобы этот метод использовался, поэтому у меня есть некоторые сомнения:

  • Безопасно ли вызывать этот метод для хранения произвольных объектов (в том смысле, что я могу быть уверен, что он будет вызван и что он не будет объявлен устаревшим/удален в ближайшее время)?
  • Чем этот метод отличается от onRetainNonConfigurationInstance(), который тоже должен возвращать Object и по сути должен работать аналогично?
  • Почему по какой-то причине лучше использовать сохраненный фрагмент?

В качестве бонуса я был бы признателен за любые другие советы или решения, чтобы сохранить состояние объектов, таких как AsyncTask, Observable, презентаторов просмотра и продолжить


person wasyl    schedule 05.06.2015    source источник
comment
stackoverflow.com/questions/15749106/   -  person petey    schedule 26.06.2015
comment
Я использую android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" для своего Activities. Взято с сайта developers.google.com/admob/android/quick-start. Предположительно, это не лучшее решение, но оно работает лучше, чем все, что я видел.   -  person Jared Burrows    schedule 29.06.2015
comment
@JaredBurrows Я ценю ваш комментарий, но разделяю мнение, что это не только не лучшее решение, но и неправильный и вредный способ обработки потери состояния в приложениях Android. Плюс это на самом деле не решает проблему (например, после того, как приложение переходит в фоновый режим)   -  person wasyl    schedule 29.06.2015
comment
Вы сами себе противоречите, и да, это делает эту проблему. Если ваше приложение работает в фоновом режиме, оно сохраняет данные (например, данные RecyclerView).   -  person Jared Burrows    schedule 29.06.2015
comment
См. stackoverflow.com/a/16305144/950427.   -  person Jared Burrows    schedule 30.06.2015
comment
@JaredBurrows: я согласен с василом в том, что ваше решение на самом деле не решает никаких проблем. В лучшем случае вы можете использовать свой подход в качестве оптимизации для действий, которые привязываются к определенной ориентации экрана. В противном случае вам все равно придется иметь дело со всеми остальными изменениями конфигурации (например, локаль, автомобильная док-станция) и теперь вам придется возиться с каждым отдельным изменением ресурса в методе onConfigurationChanged(), чтобы покрыть случаи, когда configChanges блокирует нормальный цикл уничтожения/воссоздания активности.   -  person CommonsWare    schedule 15.07.2015
comment
что он не будет объявлен устаревшим/удален в ближайшее время - он находится в библиотеке. Вы контролируете, когда берете новые версии библиотеки. Чем этот метод отличается от onRetainNonConfigurationInstance() -- onRetainNonConfigurationInstance() является final и не может быть переопределен, чтобы гарантировать, что FragmentActivity сможет выполнять работу по изменению конфигурации со своими фрагментами. onRetainCustomNonConfigurationInstance() — это замещающий хук для участия в этом на уровне активности. Почему по какой-то причине лучше использовать сохраненный фрагмент? -- он работает в местах, отличных от FragmentActivity.   -  person CommonsWare    schedule 15.07.2015
comment
Я уже сказал, что это не лучшее решение в моем комментарии. Спасибо, что согласились со мной дважды.   -  person Jared Burrows    schedule 15.07.2015
comment
@CommonsWare Спасибо! Так что в основном это мой выбор: либо использовать сохраненный фрагмент, либо пользовательский класс nonConfiguration, и оба должны работать одинаково, верно?   -  person wasyl    schedule 15.07.2015
comment
оба должны работать одинаково, верно? -- поскольку оба должны быть сохранены при изменении конфигурации, да.   -  person CommonsWare    schedule 15.07.2015


Ответы (1)


Безопасно ли вызывать этот метод для хранения произвольных объектов (в том смысле, что я могу быть уверен, что он будет вызван и что он не будет объявлен устаревшим/удален в ближайшее время)?

onRetainCustomNonConfigurationInstance() — относительно новый метод, и он не устарел. Я бы действительно предположил, что он не исчезнет в ближайшее время, потому что нет причин вводить что-то новое только для того, чтобы его удалить. Вы можете использовать его безопасно.

Чем этот метод отличается от onRetainNonConfigurationInstance(), который также должен возвращать Object и по сути должен работать аналогично?

onRetainNonConfigurationInstance() всегда возвращает экземпляр внутреннего класса NonConfigurationInstances с сохраненными фрагментами, загрузчиками и т. д. Вы не можете (и не должны) изменить это поведение системы. Вот почему метод final, и вы не можете его переопределить.

Если вы хотите сохранить свой собственный экземпляр, вам нужно переопределить onRetainCustomNonConfigurationInstance() и вернуть его оттуда.

Фактически, onRetainNonConfigurationInstance() вызывает onRetainCustomNonConfigurationInstance() и сохраняет перенастроенный экземпляр с другими состояниями, такими как сохраненные фрагменты и загрузчики.

Почему по какой-то причине лучше использовать сохраненный фрагмент?

Это скорее вопрос вашего варианта использования и предпочтений. Логика может быть такой. Если ваша активность просто контролирует фрагменты и не имеет в ней другой специальной логики, то проще использовать сохраненные фрагменты. Если в вашей активности есть что сохранить, то можете смело использовать метод onRetainCustomNonConfigurationInstance(). На данный момент в обоих случаях состояние по-прежнему сохраняется старым добрым и устаревшим onRetainNonConfigurationInstance().

p.s. Что касается бонусного вопроса о сохранении состояния, я бы посоветовал взглянуть на onSaveInstanceState(). Он был предназначен для хранения состояний.

Обновление: версия AndroidX от 5 ноября 2018 г. устарела. метод со следующим примечанием: onRetainCustomNonConfigurationInstance устарел. Используйте ViewModel для хранения объектов, которым необходимо сохранить изменения конфигурации.

person sergej shafarenka    schedule 25.06.2015
comment
Спасибо за ответ! Можете ли вы прокомментировать часть Источник активности, строка 1758, javadoc для метода onRetainNonConfigurationInstance(), в котором говорится: Эта функция вызывается исключительно для оптимизации, и вы не должны полагаться на ее вызов.? - person wasyl; 26.06.2015
comment
«onRetainNonConfigurationInstance()» устарел, поэтому вы не должны полагаться на него, и вам это не нужно, потому что вы должны либо использовать сохраненный фрагмент, либо «onRetainCustomNonConfigurationInstance()» тот, у которого нет этого предупреждения. - person sergej shafarenka; 26.06.2015
comment
Конечно, но FragmentActivity, который предоставляет onRetainCustomNonConfigurationInstance, использует onRetainNonConfigurationInstance, который в классе Activity (то есть его родителя) помечен как ненадежный. Таким образом, в FragmentActivity метод onRetainCustom... вызывается из onRetainNonConf..., который переопределяется из родителя, в то время как в родительских документах говорится, что его вызов не гарантируется. Извините, если я неясен, дайте мне знать, если мне нужно перефразировать то, что я имею в виду;) - person wasyl; 26.06.2015
comment
Я бы просто придерживался API как официального контракта между Android Framework и разработчиками. В нем говорится, что не используйте onRetainNonConfigurationInstance из-за его устаревания, и говорится, что вы можете использовать FragmentActivity.onRetainCustomNonConfigurationInstance(), потому что это общедоступный, а не устаревший метод. Тот факт, что один метод вызывает другой, ничего не должен менять. Как только устаревшие методы удаляются или не вызываются, они все равно должны каким-то образом поддерживать другой метод (поскольку он является частью официального API). Есть некоторая вероятность, что они нарушают правило, но имхо она не так высока. - person sergej shafarenka; 30.06.2015
comment
Этот ответ вместе с комментариями CommonsWare к вопросу полностью отвечает на мои вопросы, большое спасибо. - person wasyl; 15.07.2015
comment
С ноября 2018 года метод onRetainNonConfigurationInstance устарел: developer.android.com /jetpack/androidx/androidx-rn#2018-ноябрь - person Mavamaarten; 06.11.2018