Android的FragmentManager的BackStackRecord.run抛出NullPointerException

处理碎片时,我有时会遇到以下exception:

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()调用BackStackRecord run()时发生exception,当它试图从pipe理器中删除片段时。

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

我似乎无法弄清楚究竟是什么造成了这个? 我认为这与拆卸碎片时没有正确清理碎片的背后叠加有关。

回答我自己的问题:

当你调用FragmentTransaction.remove(null);时,这个exception是(最终)抛出的FragmentTransaction.remove(null); FragmentTransaction.commit();

编辑:还有,像两次盘旋和shinyuX在评论中指出; 当调用show(null)add(null)attach(null)detach(null)方法时,可能还会hide(null)

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

就我而言,我在全局对象中维护片段状态。 在那里,我检查是否显示片段,然后删除可见的碎片。 但是因为我开始了一个新的FragmentActivity,这些状态在不可见的时候仍然被设置为true。 所以这是一个devise错误。

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

我不使用标签来创build片段(他们像TabBar容器)。

所以,它改变Tab时,但如果我按下后退button,我得到了同样的错误。

在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; } } }