Когда Fragment заменяется и помещается в задний стек (или удаляется), он остается в памяти?

Является ли поведение похожим на то, как работают действия? Например, с помощью "Действия" он работает следующим образом:

Активность A запускает Активность B, а B - на экране, система может удалить A из памяти, если это необходимо системе. Нажав BACK, A будет воссоздан в память, как если бы он никогда не оставался в первую очередь.

Я искал четкое объяснение того, что происходит с памятью с Фрагментами и ничего не нашел. Это работает так же? Например:

Активность C имеет Fragment F в своем макете. Затем в какой-то момент F заменяется на Фрагмент G, но F сохраняется в своем стеке.

Будет ли F оставаться в памяти до тех пор, пока не будет убит C или он может быть удален системой по мере необходимости?

Действительно, я спрашиваю, есть ли у меня риск нехватки памяти, если у меня есть задний стек сложных фрагментов в одном действии?

Ответ 1

Взгляните на это: BackStackRecord.Op.fragment

Таким образом, фрагменты хранятся в фоновом стеке. Обратите внимание на живую ссылку, там не используются WeakReference и SoftReference.

Теперь это: FragmentManagerImpl.mBackStack

Вот где менеджер хранит задний стек. Простой ArrayList, также, не WR или SRs.

И, наконец, это: Activity.mFragments

Это ссылка на диспетчер фрагментов.

GC может собирать только объекты, которые не имеют живых ссылок (недоступны из любого потока). Это означает, что пока ваша активность не будет уничтожена (и поэтому ссылка FragmentManager исчезла), GC не сможет собрать ни одного из фрагментов в стеке.

Обратите внимание, что когда активность разрушена и сохраняет состояние (например, когда вы включаете устройство в альбомный режим), он не сохраняет фактический Fragment объектов в стеке, только их состояния - Объекты Fragment.FragmentState, то есть фактические фрагменты в обратном стеке восстанавливаются каждый раз, когда происходит действие воссоздан с сохраненным состоянием.

Надеюсь, что это поможет.

PS Итак, короче: Да, вы можете исчерпать память, добавив Fragments в back stack, а также добавив слишком много просмотров для просмотра иерархии.

UPD Учитывая ваш пример, F останется в памяти до тех пор, пока не будет убит C. Если C убит, а затем воскрешен с другой конфигурацией - F будет уничтожен и реинкарнирован в другом объекте. Таким образом, размер памяти F сохраняется до тех пор, пока C не потеряет состояние или задний стек.

Ответ 2

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

Мне пришлось добавить невероятное количество фрагментов (более ста) в цикл for для OutOfMemoryError, но это произошло. И, проверяя мои журналы, я видел, что методы onCreate() и onCreateView() вызывались много раз, но onSaveInstance(), onPause() и onDestroy вообще не вызывались.

Для справки, так я добавил фрагменты в backstack:

getSupportFragmentManager().beginTransaction().add(R.id.scene_fragment_container, mSceneFragment).addToBackStack("FOOBAR").commit();

И добавленные фрагменты были несколько простыми: ImageView, EditText, пара TextViews, SeekBar и ListView.

Но если вы не храните огромный объем данных в памяти, это не должно быть проблемой.

Позже я попробовал добавить только 50 в стопку, убив приложение и перезапустив его. И, как я надеялся/догадался, все фрагменты были восстановлены (и вызваны методы onSaveInstance() и onPause()), поэтому моя реализация жизненного цикла не была проблемой, вызвавшей срабатывание OutOfMemoryError.

Ответ 3

От developer.android.com/guide/topics/fundamentals/fragments.html

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

Ответ 4

Да, вы можете исчерпать память, создавая слишком много фрагментов в одном действии. Фрагменты будут уничтожены только в том случае, если содержит актив.