Когда фрагмент заменяется и помещается в задний стек (или удаляется), он остается в памяти? - PullRequest
71 голосов
/ 13 декабря 2011

Схоже ли поведение с тем, как работает деятельность? Например, с деятельностью это работает так:

Действие A запускается Действие B , пока на экране отображается B , система может удалить A из памяти, если она нужна система. При нажатии НАЗАД, A будет воссоздан в память, как если бы он никогда не уходил.

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

Задание C имеет Фрагмент F в своем макете. Затем в некоторый момент F заменяется на Фрагмент G , но F сохраняется в его заднем стеке.

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

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

Ответы [ 4 ]

101 голосов
/ 09 февраля 2012

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

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

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

Здесь менеджер хранит задний стек. Простой ArrayList, также без WR или SR.

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

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

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

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

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

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

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

7 голосов
/ 07 февраля 2012

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

Мне пришлось добавить невероятное количество фрагментов (более ста) в цикл 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 в backstack, убить приложение и перезапустить его. И, как я надеялся / догадался, все фрагменты были восстановлены (и вызваны методы onSaveInstance() и onPause()), поэтому моя реализация жизненного цикла не была той проблемой, которая вызвала OutOfMemoryError.

4 голосов
/ 13 декабря 2011

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

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

1 голос
/ 10 февраля 2012

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

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