Android FragmentManager BackStackRecord.run抛出NullPointerException

66

当我使用 Fragment 时,有时会遇到以下异常:

FATAL EXCEPTION: main
java.lang.NullPointerException
    at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:591)
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1416)
    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:420)
    at android.os.Handler.handleCallback(Handler.java:615)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4745)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
    at dalvik.system.NativeStart.main(Native Method)

当通过execPendingTransactions()调用BackStackRecordrun()方法时,如果它尝试从管理器中移除一个片段,则会发生异常。

case OP_REMOVE: {
  Fragment f = op.fragment;
  f.mNextAnim = op.exitAnim; <----
  mManager.removeFragment(f, mTransition, mTransitionStyle);
}
break;

我似乎无法确定究竟是什么导致了这个问题?我认为这可能与在移除片段时未正确清理片段的后退堆栈有关。

3个回答

161

回答我自己的问题:

当你调用FragmentTransaction.remove(null);FragmentTransaction.commit();时,最终会抛出此异常。

编辑:正如Twice Circled和shinyuX在评论中指出的那样; 当调用show(null)add(null)attach(null)detach(null)方法时,以及可能也包括hide(null)

在调用commit()之后,事务将排队在FragmentManager中。因此,当操作在显式调用FragmentManager.executePendingTransactions()之后被处理,或者当FragmentManager队列线程调用它时,会抛出NullPointerException异常。

在我的情况下,我在一个全局对象中维护片段状态。我检查了片段是否正在显示,然后删除了可见的片段。但是,因为我启动了一个新的FragmentActivity,这些状态仍然设置为true而不可见。因此,这是一个设计错误。

除了修复设计错误外,解决方案很简单:在删除片段之前检查FragmentManager.findFragmentByTag()是否返回null


14
好的答案 - 这帮助我解决了自己的问题。需要注意的一点是,当您调用FragmentTransaction.show(null)、.hide(null)等时,您将收到相同的错误,而不仅仅是.remove(null)。希望这可以帮助其他人追踪解决他们的问题。 - Twice Circled
1
帮了我很多!请注意,如果使用空片段发送任何操作(在我的情况下为attach detach),它将失败。 - shinyuX
1
谢谢,这确实有帮助。在我的情况下,我正在导航回到一个已销毁的FragmentActivity,在其中将对片段的引用保存在字段中。解决方案是使用findFragmentByTag并在活动的onCreate方法中重新分配这些字段 - 如果savedInstanceState!= null(在这种情况下,片段不会被重新创建 - 请参见此处)。 - kassim
2
这应该在实际的hide,show调用时完全崩溃,以便堆栈跟踪实际上可用... - njzk2
我调用了“replace”函数,而且参数不为空。为什么我仍然会遇到这个问题? - android developer
显示剩余2条评论

0

发生这种情况的唯一原因是调用了

getSupportFragmentManager().beginTransaction().remove(fragment)

fragment 为空时


-2

我不使用标签来创建片段(它们像TabBar容器一样工作)。

因此,在更改选项卡时它可以工作,但如果我按返回按钮,我会得到相同的错误。

在onDestroyView方法中,我发现了一个片段实例,使用FragmentManager#findFragmentById,然而FragmentManager#findFragmentByTag则返回null。

class MyFragment extends ListFragment {

@Override
public void onDestroyView() {
    super.onDestroyView();

    if (this.mapFragment != null
            && getFragmentManager().findFragmentById(
                    this.mapFragment.getId()) != null) {

        getFragmentManager().beginTransaction().remove(this.mapFragment)
                .commit();
        this.mapFragment = null;
    }

}
}

2
为什么需要将mapFragment设置为null? - IgorGanapolsky
1
一个值得回答的编程问题:为什么有必要将mapFragment设置为null? - nmxprime

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接