PagerAdapter.getItem() 崩溃并出现 IllegalStateException:片段已添加

PagerAdapter.getItem() crash with IllegalStateException: Fragment already added

我有 FragmentStatePagerAdapter.getItem() 的代码:

(logd()只是调用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;
}

但它总是崩溃:

    --------- 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.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)

这让我完全难住了。有人可以帮助解释为什么会发生这种崩溃吗?

据我所知,相同的代码结构在我的应用程序的其他地方也有效。

我确实看到了其他几个具有相同异常的 SO 问题,但是 none 专门处理 ViewPager+TabLayout 组合中的片段。

编辑:即使这段代码也会因同样的异常而崩溃:

@Override
public Fragment getItem(int position) {

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

编辑:添加 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;
}

编辑:

似乎如果我 return 从 getItem() 新建 Fragment(),一切正常。如果我 return 从 getItem() 新建 MyCustomFragment(),我就会崩溃。 MyCustomFragment 甚至没有任何构造函数;它依赖于默认的(尽管我确实尝试使用仅调用 super() 的无参数构造函数;但崩溃仍然存在)。

您不能在其他地方使用已添加的 Fragment。当这行代码执行时:

currFragment = allFragments.get(position);

根据log,这意味着您列表中的fragment已经添加到某个地方(在不同的地方或非常相同的地方)。也就是说,在getItem(int position)中,只能添加一个Fragment的新实例。所以删除这个代码块:

else {

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

这个 exception 应该消失了。

问题在于,在 MyCustomFragment 中,在 onCreateView() 方法中,return super.onCreateView() 的 IDE-stub 代码被无意中留在原地。超类 Fragment 在某些条件下从其 onCreateView() 中 returns null。看来是来自 onCreateView() 的 null return 造成了问题。我在 MyCustomFragment 的 onCreateView() 中膨胀了一个测试布局,现在崩溃消失了。

如果情况确实如此,则例外情况看起来措辞不正确。