0

I have this code for FragmentStatePagerAdapter.getItem():

(logd() is just a static method that calls Log.d()).

@Override
public Fragment getItem(int position) {

    logd("Fragment for position: " + position);

    Fragment currFragment = null;
    List<Fragment> allFragments = mFragmentManager.getFragments();
    if (allFragments.size() == 0) {

        logd("No Fragments cached.");
    } else {

        currFragment = allFragments.get(position);
        logd("Found a cached Fragment: " + currFragment);
    }

    if (currFragment == null) {

        currFragment = MyCustomFragment.create(position);
    }

    logd("Returning Fragment: Position: " + position + " Fragment: " + currFragment.toString());
    return currFragment;
}

But it keeps crashing with:

    --------- beginning of crash
2020-07-27 10:45:44.492 6271-6271/com.example.package E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.package, PID: 6271
    java.lang.IllegalStateException: Fragment already added: MyCustomFragment{7c7e778} (5f284a0f-a00f-4be2-8098-a3e8dc65c9cb) id=0x7f09024e}
        at androidx.fragment.app.FragmentStore.addFragment(FragmentStore.java:67)
        at androidx.fragment.app.FragmentManager.addFragment(FragmentManager.java:1563)
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:405)
        at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2167)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1990)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1945)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1847)
        at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6592)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)

This has me totally stumped. Can someone help why this crash is happening?

As far as I can make out, the same code construct works elsewhere in my app.

I did see several other SO questions with the same exception, but none that dealt specifically with Fragments inside ViewPager+TabLayout combinations.

Edit: Even this code crashes with the same exception:

@Override
public Fragment getItem(int position) {

    Fragment currFragment = MyCustomFragment.create(position);
    logd("Returning Fragment: Position: " + position + " Fragment: " + currFragment.toString());
    return currFragment;
}

Edit: Adding the code of MyCustomFragment.create():

public static MyCustomFragment create(int position) {

    Bundle args = new Bundle();
    args.putInt("position", position);
    MyCustomFragment f = new MyCustomFragment();
    f.setArguments(args);
    logd("Creating Fragment at position: " + position);
    return f;
}

Edit:

It seems that if I return new Fragment() from getItem(), everything works. If I return new MyCustomFragment() from getItem(), I get the crash. MyCustomFragment does not even have any constructor; it relies on the default one (though I did try with a no-arg constructor that just calls super(); still the crash persists).

FreeBird
  • 691
  • 1
  • 8
  • 18

2 Answers2

0

You cannot use an already added Fragment in another place. When this line of code is executing:

currFragment = allFragments.get(position);

according to the log, it means the fragment in you list is already added somewhere (in a different place or very same place). In other words, in getItem(int position), you can only add a new instance of a Fragment. So remove this code block:

else {

    currFragment = allFragments.get(position);
    logd("Found a cached Fragment: " + currFragment);
}

And this exception should go away.

sajjad
  • 834
  • 6
  • 13
  • With only this much: @Override public Fragment getItem(int position) { Fragment currFragment = MyCustomFragment.create(position); logd("Returning Fragment: Position: " + position + " Fragment: " + currFragment.toString()); return currFragment; } I still get the exception. – FreeBird Jul 27 '20 at 06:25
  • Would you mind sharing the code at which Exception occurs? Specifically this part: `FragmentStore.addFragment(FragmentStore.java:67)` – sajjad Jul 27 '20 at 06:37
  • FragmentStore is a framework class (androidx.fragment.app.FragmentStore). The relevant method is: void addFragment(@NonNull Fragment fragment) { if (mAdded.contains(fragment)) { throw new IllegalStateException("Fragment already added: " + fragment); } synchronized (mAdded) { mAdded.add(fragment); } fragment.mAdded = true; } – FreeBird Jul 27 '20 at 06:45
0

The problem was that within MyCustomFragment, in the onCreateView() method, the IDE-stub code of return super.onCreateView() was left in place inadvertently. The superclass, Fragment, returns null from its onCreateView() under certain conditions. It appears that this null return from onCreateView() was creating the problem. I inflated a test layout in MyCustomFragment's onCreateView() and now the crash is gone.

The exception looks incorrectly worded if that is indeed the case.

FreeBird
  • 691
  • 1
  • 8
  • 18