FragmentManager уже выполняет транзакции. Когда безопасно инициализировать пейджер после фиксации?
У меня есть активность, в которой размещаются два фрагмента. Действие начинается с отображения загрузчика при загрузке объекта. Загруженный объект затем передается обоим фрагментам в качестве аргументов с помощью методов newInstance и прикрепляются эти фрагменты.
final FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.container1, Fragment1.newInstance(loadedObject));
trans.replace(R.id.container2, Fragment2.newInstance(loadedObject));
trans.commit();
Второй фрагмент содержит android.support.v4.view.ViewPager и вкладки. onResume мы инициализируем его следующим образом
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(adapter.getCount()); //the count is always < 4
tabLayout.setupWithViewPager(viewPager);
Проблема в том, что андроид затем бросает
java.lang.IllegalStateException: FragmentManager уже выполняет транзакции
С этой трассировкой стека: (я взял android.support
из имен пакетов только для краткости)
v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:1620) в v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:637) в v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:143) в v4.view.ViewPager.populate(ViewPager.java:1235) в v4.view.ViewPager.populate(ViewPager.java:1083) в v4.view.ViewPager.setOffscreenPageLimit(ViewPager.java:847)
Данные показывают, если setOffscreenPageLimit(...);
удален. Есть ли другой способ избежать этой проблемы?
Когда в жизненном цикле завершена транзакция фрагмента, так что я могу подождать, чтобы настроить мой пейджер?
Ответы
Ответ 1
Если вы нацеливаете sdk 24 и выше, вы можете использовать:
FragmentTransaction.commitNow()
вместо commit()
Если вы ориентируетесь на более старые версии, попробуйте позвонить:
FragmentManager.executePendingTransactions()
после вызова commit()
Ответ 2
Просто используйте childFragmentManger()
для viewpager
внутри Fragment
mPagerAdapter = new ScreenSlidePagerAdapter(getChildFragmentManager());
mPager.setAdapter(mPagerAdapter);
Ответ 3
У меня было это исключение, когда мы быстро заменили 2 фрагмента И используя executePendingTransactions(). Не назвав этого, не было никаких исключений.
В чем дело? Я открываю фрагмент A и в его onResume() (при условии) я прошу операцию заменить фрагмент фрагментом B. В этот момент возникает исключение.
Моим решением было использовать Handler.post(runnable), который помещает запрос в конец очереди потоков, а не запускает его немедленно. Таким образом мы гарантируем, что новая транзакция будет выполнена после завершения любых предыдущих транзакций.
Поэтому мое решение было таким простым, как:
Handler uiHandler = new Handler();
uiHandler.post(new Runnable()
{
@Override
public void run()
{
openFragmentB(position);
}
});
Ответ 4
Если кто-то использует Robolectric> 3.6 и, по крайней мере, до 4.0.2 с ViewPager, вы можете увидеть это даже с правильным кодом.
В этой проблеме GitHub есть соответствующая информация, отслеживающая проблему для Robolectric.
Проблема не решена, когда я пишу этот ответ, и единственные известные обходные пути - это использовать @Config (sdk = {27}), который, кажется, работает для некоторых, но не работает для меня, или реализовать ViewPagerShadow с обходным решением в вашем тестовый пакет с довольно длинным кодом, на который ссылается github (я могу включить его здесь, если это лучше, но это может быть недостаточно актуально в качестве ответа?) и использовать @Config (shadows = {ShadowViewPager.class})
Ответ 5
У меня была похожая проблема,
Фрагмент добавления основной активности A.
Затем фрагментA обратного вызова основной деятельности, чтобы заменить себя фрагментом B.
MainActivity генерирует исключение "фрагмент-менеджер уже выполняет транзакцию", когда заменяет и фиксирует транзакцию с фрагментом B.
Проблема на самом деле происходит от фрагмента B.
У меня есть TabHost во фрагменте B, который требует getfragmentmanager() для добавления tabfragment.
Замените getfragmentmanager() на getchildfragmentmanager() во фрагменте B, чтобы решить эту проблему.
Ответ 6
Я использовал/расширил свой адаптер с FragmentStatePagerAdapter
вместо FragmentPagerAdapter
, это решило мою проблему.
Используйте FragmentStatePagerAdapter
, если фрагменты являются динамическими и часто меняются во время выполнения.
Используйте FragmentPagerAdapter
, если фрагменты статичны и НЕ меняются часто во время выполнения.
просвещенный из этой статьи,https://medium.com/inloopx/adventures-with-fragmentstatepageradapter-4f56a643f8e0