Зачем использовать Fragment # setRetainInstance (boolean)?

Мне кажется, что Fragment # setRetainInstance (true) сбивает меня с толку. Вот Javadoc, извлеченный из Android Developer API:

public void setRetainInstance (логическое сохранение)

Управляйте сохранением экземпляра фрагмента при повторном создании Activity (например, при изменении конфигурации). Это можно использовать только с фрагментами, не находящимися в заднем стеке. Если установлено, жизненный цикл фрагмента будет немного отличаться при воссоздании действия:

  • onDestroy () не будет вызываться (но onDetach () все равно будет, потому что фрагмент отключается от его текущей активности).
  • onCreate (Bundle) не будет вызываться, поскольку фрагмент не создается повторно.
  • onAttach (Activity) и onActivityCreated (Bundle) будут вызываться.

Вопрос: как вы, как разработчик, используете это и почему это упрощает работу?


person Håvard Geithus    schedule 22.06.2012    source источник
comment
аналогичный вопрос с хорошей информацией: Понимание setRetainInstance фрагмента (логическое значение)   -  person Richard Le Mesurier    schedule 11.10.2012
comment
onDestroy() будет вызываться, если на устройстве мало памяти   -  person James Goodwin    schedule 25.01.2016


Ответы (4)


Как вы, как разработчик, используете это

Позвоните setRetainInstance(true). Я обычно делаю это в onCreateView() или onActivityCreated(), где я это использую.

и почему это облегчает жизнь?

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

person CommonsWare    schedule 22.06.2012
comment
@CommonsWare - если вы создаете новый фрагмент в Activity и это Activity воссоздается, как избежать повторного создания нового фрагмента? - person Neil; 20.10.2012
comment
@Neil: Посмотрите, существует ли фрагмент (например, findFragmentById()). Не воссоздайте его, если он существует. - person CommonsWare; 20.10.2012
comment
@CommonsWare Если фрагмент немного перегружен представлениями и использованием памяти, что, по вашему мнению, должен делать хороший разработчик? - person android developer; 21.04.2013
comment
@androiddeveloper: представления не являются проблемой, пока фрагмент не удерживает их напрямую, поскольку они всегда отбрасываются и воссоздаются. Я не совсем уверен, насколько тяжелым будет сам фрагмент с точки зрения использования памяти - у вас есть пример? - person CommonsWare; 21.04.2013
comment
@CommonsWare. Если фрагмент содержит свои представления, так что ему не придется создавать их повторно (в методе onCreate ()), это может занять некоторую память. Однако я думаю, что для этой задачи можно использовать softReference / weakReference, не так ли? - person android developer; 21.04.2013
comment
@androiddeveloper: если фрагмент содержит свои представления, так что ему не придется их воссоздавать (в методе onCreate ()), это может занять некоторую память - вы можете попытаться переназначить виджеты в новое занятие, но мне с этим не повезло. AFAIK, вам нужно воссоздать виджеты в onCreateView(). Однако я думаю, что для этой задачи можно использовать softReference / weakReference, не так ли? - какая задача? - person CommonsWare; 21.04.2013
comment
@CommonsWare Это возможно. Вы проверяете родительский элемент представления, который был сохранен ранее (проверяйте, конечно, на null), и, если родительский элемент существует, вы удаляете фрагмент из его родительского элемента. Конечно, в некоторых случаях это может не сработать, поэтому вам всегда нужно размещать фрагменты в одном макете и никогда не помещать в макет другие представления. Под задачей я имел в виду то, что без проблем не нужно пересоздавать просмотры. - person android developer; 21.04.2013
comment
@CommonsWare Можно ли вызвать setRetainInstance (true) в onCreate ()? - person e.shishkin; 03.05.2013
comment
@ e.shishkin: Так и должно быть. Я редко реализую onCreate() во фрагменте, поэтому не пробовал. - person CommonsWare; 03.05.2013
comment
@ e.shishkin Вы можете звонить в любое время, когда захотите. Технически вам даже не нужно вызывать его в методах жизненного цикла (хотя, как правило, это не то, что вам когда-либо нужно / нужно делать). - person Alex Lockwood; 21.08.2013
comment
Будет ли это применяться к ListFragment, если пользователю нужно погрузиться в иерархию, а затем к getRetainInstance (), если пользователь нажимает кнопку «Назад»? Или общей практикой является использование addToBackStack для воссоздания прошлого ListFragment, если это двухпанельное приложение? - person whyoz; 20.03.2014
comment
@whyoz: Простите, но я не понимаю, о чем вы говорите. - person CommonsWare; 20.03.2014
comment
ListFragment 1 (нажмите listView row, подтвердите транзакцию) ››› ListFragment 2 ››› (нажмите) НАЗАД КНОПКА ››› получение / восстановление ListFragment 1 без перезагрузки данных - person whyoz; 20.03.2014
comment
@CommonsWare поможет ли это повторно открыть приложение из списка последних приложений и сохранить состояние фрагмента? - person Raghavendra; 14.10.2015
comment
@Raghavendra: Только если процесс еще не закончился. - person CommonsWare; 14.10.2015
comment
@CommonsWare благодарим за ответ. Можете ли вы дать мне решение моей проблемы. У меня есть фрагмент, который содержит список, когда я нажимаю кнопку `` Домой '', и предположим, что если запускается сборщик мусора, я потерял свои данные, которые являются списком, когда я пытаюсь снова открыть приложение, оно вылетает. ты можешь мне в этом помочь? - person Raghavendra; 14.10.2015

Это очень помогает держать открытыми долго работающие ресурсы, такие как сокеты. Имейте фрагмент без пользовательского интерфейса, содержащий ссылки на сокеты Bluetooth, и вам не придется беспокоиться о их повторном подключении, когда пользователь переворачивает телефон.

Также удобно хранить ссылки на ресурсы, загрузка которых занимает много времени, например растровые изображения или данные сервера. Загрузите его один раз, сохраните в сохраненном фрагменте, и когда действие перезагружается, оно все еще там, и вам не нужно его перестраивать.

person DeeV    schedule 22.06.2012
comment
Отлично. Но что, если нам нужно их обновить? - person Anshul Tyagi; 04.03.2016
comment
Я ошибаюсь, думая, что это то, что обычно делает синглтон? - person rupinderjeet; 09.06.2021
comment
@rupinderjeet да. Синглтон - еще один способ сделать это. Синглтоны считаются антипаттернами, и некоторые люди не решаются их использовать. Фрагменты также имеют то преимущество, что они привязаны к жизненному циклу действия, поэтому вы получаете события жизненного цикла. Вы можете уничтожить ресурс, например, если пользователь покидает приложение (что также можно сделать с помощью Singleton, но требует больше кода). - person DeeV; 10.06.2021

Добавил этот ответ очень поздно, но я подумал, что это прояснит ситуацию. Скажи за мной. Когда setRetainInstance:

ЛОЖЬ

  • При изменении конфигурации фрагмент создается заново. НОВЫЙ ЭКЗЕМПЛЯР создан.
  • ВСЕ методы жизненного цикла вызываются при изменении конфигурации, включая onCreate() и onDestroy().

ИСТИНА

  • Фрагмент не создается повторно при изменении конфигурации. ИСПОЛЬЗУЕТСЯ ТО ЖЕ ЭКЗЕМПЛЯР.
  • Все методы жизненного цикла вызываются при изменении конфигурации APART FROM onCreate() и onDestroy().
  • Сохранение экземпляра не сработает при добавлении в backstack.

Не забывайте, что вышесказанное относится как к DialogFragment, так и к фрагментам.

person Eurig Jones    schedule 08.09.2013
comment
Вы можете добавить ссылку на Retaining an instance will not work when added to the backstack. ? - person nmxprime; 13.06.2014
comment
@nmxprime здесь: developer.android.com/reference/android / app / - person android developer; 03.07.2014
comment
Как восстановить состояние фрагмента, если он был добавлен в бэк-стек? saveInstanceState имеет значение null, и я не могу использовать setRetainInstance ... - person android developer; 27.08.2014

Метод setRetainInstance (boolean) устарел, используйте вместо него ViewModels.

Метод setRetainInstance(boolean) для фрагментов устарел, поскольку версии 1.3.0 API фрагментов.

С введением ViewModels у разработчиков появился специальный API для сохранения состояния, который может быть связаны с графиками действий, фрагментов и навигации. Это позволяет разработчикам использовать обычный, а не сохраняемый фрагмент и отдельно сохранять конкретное состояние, которое они хотят сохранить.

Это гарантирует, что у разработчиков будет гораздо более понятный жизненный цикл для этих Фрагментов (тот, который соответствует всем остальным их Фрагментам) при сохранении полезных свойств единственного создания и единственного уничтожения (в данном случае конструктора ViewModel и onCleared() обратный звонок от ViewModel).

person Darish    schedule 12.03.2020