android(18): Fragment常见的坑 - clarkehe/Android GitHub Wiki
异常
java.lang.IllegalStateException: Fragment a{3b4d2620} not attached to Activity
android.support.v4.app.Fragment.getResources(ProGuard:639)
原因分析:
异常1
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
android.support.v4.app.FragmentManagerImpl.checkStateLoss(ProGuard:1489)
android.support.v4.app.FragmentManagerImpl.enqueueAction(ProGuard:1507)
android.support.v4.app.BackStackRecord.commitInternal(ProGuard:634)
android.support.v4.app.BackStackRecord.commit(ProGuard:613)
android.support.v4.app.DialogFragment.show(ProGuard:139)
异常2
java.lang.IllegalStateException: Activity has been destroyed
android.support.v4.app.FragmentManagerImpl.enqueueAction(ProGuard:1511)
android.support.v4.app.BackStackRecord.commitInternal(ProGuard:634)
android.support.v4.app.BackStackRecord.commitAllowingStateLoss(ProGuard:617)
原因分析: 第一个异常是使用DialogFragment出现的异常。DialogFragment本质还是添加一个Fragment到Host Activity中。看下DialogFragment的show的实现:
/**
* Display the dialog, adding the fragment to the given FragmentManager. This
* is a convenience for explicitly creating a transaction, adding the
* fragment to it with the given tag, and committing it. This does
* <em>not</em> add the transaction to the back stack. When the fragment
* is dismissed, a new transaction will be executed to remove it from
* the activity.
* @param manager The FragmentManager this fragment will be added to.
* @param tag The tag for this fragment, as per
* {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}.
*/
public void show(FragmentManager manager, String tag) {
mDismissed = false;
mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();
}
异常1是说在Add Fragment时,Host Activity是已经调用了onSaveInstanceState,此时Host Activity一般是退到了后台。onSaveInstanceState是保存Activity的状态,在Activity被回收后,方便进行恢复。onSaveInstanceState之后Add Fragment,Fragment没有机会再保存状态,回收了没有数据进行恢复。
解决方法有好几种,最简单的是自己实现show的方法,在Add Fragment时,使用commitAllowingStateLoss,允许Fragment状态丢失。
FragmentManager fm = fragmentActivity.getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(this, this.getClass().getSimpleName());
ft.commitAllowingStateLoss();
还有一种方法时,将Add Fragment的时机延迟到Activity的onResume方法。
异常2也是Host Activity的生命周期问题。在Add Fragment时,Host Activity是已经Destroy了。此时Add Fragment已经没有意义了。处理起来很简单,在Add Fragment前判断下Host Activity的状态,如果Destroy了,就直接返回。
if (fragmentActivity == null || fragmentActivity.isFinishing() || isAdded()) {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if(fragmentActivity.isDestroyed()) {
return;
}
}