Моя проблема
Согласно документам Google:
Теперь вы можете вставлять фрагменты внутрь фрагментов. Это полезно в различных ситуациях, когда вы хотите поместить динамические и повторно используемые компоненты пользовательского интерфейса в компонент пользовательского интерфейса, который сам по себе является динамическим и повторно используемым. Например, если вы используете ViewPager для создания фрагментов пролистывания влево и вправо и занимают большую часть экрана, вы теперь можете вставлять фрагменты в каждую страницу фрагмента. . Чтобы вложить фрагмент, просто вызовите getChildFragmentManager() для фрагмента, в который вы хотите добавить фрагмент. Это возвращает FragmentManager, который вы можете использовать, как обычно, из активности верхнего уровня для создания транзакций фрагментов. Например, вот код, который добавляет фрагмент из существующего класса Fragment:
Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();
Поэтому я создал свой собственный PageFragment
. А мой PageFragmentAdapter
состоит из 3-х страниц PageFragment
. У меня также есть шесть фрагментов: Fragment1
, Fragment2
, Fragment3
, FragmentA
, FragmentB
, FragmentC
. В своем MainActivity
я инициализирую свои шесть фрагментов, свой ViewPager
и его PageFragmentAdapter
(которые инициализируют три PageFragment
для себя).
Затем я использую этот метод, чтобы прикрепить свои Fragment1
, Fragment2
, Fragment3
к каждой странице (к каждому PageFragment
) PageFragmentAdapter
:
PageFragmentAdapter tPageFragmentAdapter = new PageFragmentAdapter(getSupportFragmentManager());
tPageFragmentAdapter.setFirstPage(tFragment1);
tPageFragmentAdapter.setSecondPage(tFragment2);
tPageFragmentAdapter.setThirdPage(tFragment3);
Я могу получить (с помощью методов в PageFragmentAdapter
) фрагменты и сделать «вложенный фрагмент» в свой PageFragment
(конечно, в onCreate()
), например:
getChildFragmentManager().beginTransaction()
.add(R.id.framelayout_history, mFragment)
.addToBackStack(null)
.commit();
Примечание. Я использую PageFragment.setNestedFragment()
, чтобы установить в нем mFragment
.
И это прекрасно работает! Мне поможет (но этот рассказ не об этом) простая замена фрагментов во ViewPager типа:
tPageFragmentAdapter.replaceFirstPage(tFragmentA);
Но у меня есть одна огромная проблема. Снова документы Google:
Реализация PagerAdapter, которая представляет каждую страницу как фрагмент, который постоянно хранится в диспетчере фрагментов, пока пользователь может вернуться на страницу. Эта версия пейджера лучше всего подходит для использования, когда есть несколько обычно более статических фрагментов, которые нужно просмотреть, например, набор вкладок. Фрагмент каждой страницы, которую посещает пользователь, будет храниться в памяти, хотя его иерархия представлений может быть уничтожена, если она не видна. Это может привести к использование значительного объема памяти, поскольку экземпляры фрагментов могут удерживать произвольное количество состояний.
Как видите, PageFragmentAdapter
может уничтожить каждый мой PageFragment
и, конечно же, его вложенный фрагмент. И когда он будет воссоздан, он будет иметь значение NULL вместо mFragment
. Я пытаюсь сохранить его через getChildFragmentManager().putFragment()
, а затем получить через getChildFragmentManager().getFragment()
. Но это не сработало.
Вопрос
Итак, мой вопрос: Как сохранить мой вложенный фрагмент в моем родительском фрагменте? Возможно ли это?
Я был бы очень признателен за вашу помощь. Алекс. P.S. Очень извиняюсь за мой английский :)
РЕДАКТИРОВАТЬ
Спасибо @AndroidBegin.com за ответ!
Похоже, это ошибка недавно добавленной поддержки вложенных фрагментов. По сути, дочерний FragmentManager завершается с нарушенным внутренним состоянием, когда он отсоединяется от активности. Краткосрочное обходное решение, которое исправило это для меня, состоит в том, чтобы добавить следующее в onDetach() каждого фрагмента, который вы вызываете getChildFragmentManager():
@Override
public void onDetach() {
super.onDetach();
try {
Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
childFragmentManager.setAccessible(true);
childFragmentManager.set(this, null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}