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