问题
Context: I have an Activity
with a Fragment
and 3 InnerFragments
. When the Fragment
onDestroy()
is called, I want to remove the inner fragments from the FragmentManager
. The code from onDestroy()
is below.
Problem: FragmentManager
throws NullPointerException
, probably when commitAllowingStateLoss()
is called. I don't understand why.
@Override
public void onDestroy()
{
super.onDestroy();
if (getFragmentManager().findFragmentById(R.id.fragment_framelayout_left) != null)
{
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.remove(mLeftFragment);
fragmentTransaction.commitAllowingStateLoss();
}
}
Stack trace:
02-11 12:15:14.162: E/AndroidRuntime(25911): FATAL EXCEPTION: main
02-11 12:15:14.162: E/AndroidRuntime(25911): java.lang.NullPointerException
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1419)
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429)
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.os.Handler.handleCallback(Handler.java:725)
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.os.Handler.dispatchMessage(Handler.java:92)
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.os.Looper.loop(Looper.java:137)
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.app.ActivityThread.main(ActivityThread.java:5039)
02-11 12:15:14.162: E/AndroidRuntime(25911): at java.lang.reflect.Method.invokeNative(Native Method)
02-11 12:15:14.162: E/AndroidRuntime(25911): at java.lang.reflect.Method.invoke(Method.java:511)
02-11 12:15:14.162: E/AndroidRuntime(25911): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
02-11 12:15:14.162: E/AndroidRuntime(25911): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
02-11 12:15:14.162: E/AndroidRuntime(25911): at dalvik.system.NativeStart.main(Native Method)
回答1:
The FragmentManager
manages all Fragments
at the Activity
level, and their lifecycle will be tied to that parent Activity
. The child Fragment
manager manages all Fragments
at the Fragment
level, and their lifecycle will be tied to that parent Fragment
.
So for your phone architecture, add your InnerFragment
to your Activity
using getFragmentManager()
. When the Activity
destroys for good (via back button / finish()
), the FragmentManager
will destroy and release the InnerFragment
for you.
For your tablet architecture, add your InnerFragments
to your Fragment
using getChildFragmentManager()
(in the latest support library). When the Fragment
destroys for good, the FragmentManager
will destroy and release the InnerFragments
for you.
You should not have to manage releasing and destroying your Fragments
yourself. I'd recommend logging the lifecycle events of your Activities
and Fragments
so you can watch them go through their states and ensure correct behavior.
回答2:
The NullPointerException is caused by the fact that Activity's Handler is unset from the FragmentManager, so a "solution" that will prevent the crash is the following:
public void onDestroy(){
super.onDestroy();
try {
Field mActivityField = getFragmentManager().getClass().getDeclaredField("mActivity");
mActivityField.setAccessible(true);
mActivityField.set(getFragmentManager(), this);
Field mPendingActionsField = getFragmentManager().getClass().getDeclaredField("mPendingActions");
mPendingActionsField.setAccessible(true);
mPendingActionsField.set(getFragmentManager(), null);
Field f = Activity.class.getDeclaredField("mHandler");
f.setAccessible(true);
Handler handler = (Handler) f.get(this);
handler.close();
} catch (Throwable e) {
}
}
回答3:
CASE: When you need to call Fragment(Child fragment) from another Fragment(Parent Fragment)
always use getChildFragmentManager()
instead of getFragmentManager
inside your Parent Fragment.
Read documentation
来源:https://stackoverflow.com/questions/14810183/fragmentmanager-nullpointerexception-when-trying-to-commitallowingstateloss