Question

[Solved] FragmentManager is already executing transactions. When is it safe to initialise pager after commit?

I have an activity hosting two fragments. The activity starts off showing a loader while it loads an object. The loaded object is then passed to both fragments as arguments via newInstance methods and those fragments are attached.

final FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.container1, Fragment1.newInstance(loadedObject));
trans.replace(R.id.container2, Fragment2.newInstance(loadedObject));
trans.commit();

The second fragment contains a android.support.v4.view.ViewPager and tabs. onResume we initialise it like follows

viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(adapter.getCount()); //the count is always < 4
tabLayout.setupWithViewPager(viewPager);

The problem is android then throws

java.lang.IllegalStateException: FragmentManager is already executing
transactions

With this stack trace: (I took android.support out of the package names just for brevity)

v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:1620)
at
v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:637)
at
v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:143)
at v4.view.ViewPager.populate(ViewPager.java:1235)
at v4.view.ViewPager.populate(ViewPager.java:1083)
at
v4.view.ViewPager.setOffscreenPageLimit(ViewPager.java:847)

The data shows if setOffscreenPageLimit(...); is removed. Is there another way to avoid this issue?

When in the lifecycle is the fragment transaction complete so that I can wait to setup my pager?

Solution #1:

If you’re targeting sdk 24 and above you can use:

FragmentTransaction.commitNow()

instead of commit()

If you’re targeting older versions, try calling:

FragmentManager.executePendingTransactions()

after the call to commit()

Respondent: marmor

Solution #2:

Simply use childFragmentManger() for viewpager inside a Fragment

mPagerAdapter = new ScreenSlidePagerAdapter(getChildFragmentManager());
mPager.setAdapter(mPagerAdapter);
Respondent: Hitesh Sahu

Solution #3:

I had this exception when quickly replacing 2 fragments AND using executePendingTransactions(). Without calling this there was no exception.

What was my case?
I open a fragment A and in its onResume() (under a condition) I ask the activity to replace the fragment with fragment B. At that point the exception occurs.

My solution was to use a Handler.post(runnable) which places the query on the end of the thread queue instead of running it immediately. This way we ensure that the new transaction will be executed after any previous transactions are completed.

So my solution was as simple as:

Handler uiHandler = new Handler();
uiHandler.post(new Runnable()
{
    @Override
    public void run()
    {
        openFragmentB(position);
    }
});
Respondent: M.Paunov

Solution #4:

I Had a similar issue,

A mainAcitivity adding fragmentA.

Then fragmentA callback mainactivity to replace itself with fragmentB.

MainActivity throw exception “fragmentmanager already executing transaction” when replace and commit transaction with fragmentB.

The issue actually comes from fragmentB.

I have a TabHost in fragment B which require getfragmentmanager() to add tabfragment.

Replace getfragmentmanager() by getchildfragmentmanager() in fragmentB solve the issue.

Respondent: Alexandre Levieux

Solution #5:

Got a similar error not connected to question but hops its helps someone when working with firebase.
Remove activity, requireActivity or this from .addSnapshotListener(), keep it blank.

 videosListener = videosCollectionRef
            .addSnapshotListener() { snapshot, exception ->

                if (exception != null) {
                    Log.e("Exception", "Could not retrieve documents: $exception")
                }

                if (snapshot != null) {
                    parseData(snapshot)
                }
            }

Solution #6:

I had same problem. However, I was using the FragmentStateAdapter constructor that gets only the FragmentActivity:

package androidx.viewpager2.adapter;

public FragmentStateAdapter(
    @NonNull FragmentActivity fragmentActivity
) {
    this(fragmentActivity.getSupportFragmentManager(), fragmentActivity.getLifecycle());
}

Even though it gets the Lifecycle from fragmentActivity instance, it was not working at all.

Then, diving into the code of the FragmentStateAdapter, I saw there is another constructor where you can pass the Lifecycle instance.

package androidx.viewpager2.adapter;

public FragmentStateAdapter(
    @NonNull FragmentManager fragmentManager,
    @NonNull Lifecycle lifecycle
) {
    mFragmentManager = fragmentManager;
    mLifecycle = lifecycle;
    super.setHasStableIds(true);
}

So, I changed my PageAdapter constructor to receive the FragmentManager as childFragmentManager and the LifeCycle from the viewLifecycleOwner. And pass those parameters to the FragmentStateAdapter constructor:

class MyPagerAdapter(
    fragmentManager: FragmentManager,
    lifecycle: Lifecycle
) : FragmentStateAdapter(fragmentManager, lifecycle) {
  //...
}

Then, when calling my PagerAdapter constructor, I pass the FragmentManager and
I get the lifeCycle from the viewLifecycleOwner:

val myPagerAdapter = MyPagerAdapter(
    fragmentManager = childFragmentManager,
    lifecycle = viewLifecycleOwner.lifecycle
)

[UPDATE]
MyPagerAdapter is set from a Fragment.

Respondent: Jesse Lima

Solution #7:

If anyone is using Robolectric >3.6 and at least through 4.0.2 with a ViewPager you may see this even with correct code.

There is related information in this github issue tracking the problem for Robolectric.

The issue is not resolved as I write this answer, and the only workarounds known are to use @Config(sdk={27}) which appears to work for some but did not work for me, or implement a ViewPagerShadow with a workaround in your test package with the rather-long code referenced on github (I can include it here if that is better but this may not be relevant enough as an answer?) and use @Config(shadows={ShadowViewPager.class})

Respondent: Mike Hardy

Solution #8:

I used/extended my adapter with FragmentStatePagerAdapter instead of FragmentPagerAdapter this resolved my issue.

Use FragmentStatePagerAdapterif the fragments are dynamic and are changing frequently during run-time.

Use FragmentPagerAdapter if the fragments are static and do NOT change frequently during run-time.

enlightened from this article,
https://medium.com/inloopx/adventures-with-fragmentstatepageradapter-4f56a643f8e0

Respondent: Karthik H

Solution #9:

ViewPager2

It is quite an old answer from the time of ViewPager and has helped many to solve the issue who came across this. Just in case you are having ViewPager2 and face similar issue then,

We know this happens when we have ViewPager2 inside a fragment and FragmentStateAdapter class has a constructor with Fragment parameter, so you can use that to create your adapter.

Like,

class ScreenSlidePagerAdapter(fragment: Fragment): FragmentStateAdapter(fragment)

Then,

val pagerAdapter = ScreenSlidePagerAdapter(this)
Respondent: gprathour

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Most Popular

To Top
India and Pakistan’s steroid-soaked rhetoric over Kashmir will come back to haunt them both clenbuterol australia bossier man pleads guilty for leadership role in anabolic steriod distribution conspiracy