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队列线程调用该操作时,会抛出NullPointerException
exception。
就我而言,我在全局对象中维护片段状态。 在那里,我检查是否显示片段,然后删除可见的碎片。 但是因为我开始了一个新的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; } } }