问题描述

public class MatchFragment extends BaseFragment {    public static final String TAG = MatchFragment.class.getSimpleName();    private FragmentManager mFragmentManager;    public MatchFragment() {        // Required empty public constructor    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,            Bundle savedInstanceState) {        // Inflate the layout for this fragment        View view = inflater.inflate(R.layout.fragment_match, container, false);        mFragmentManager = getChildFragmentManager();        FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();        fragmentTransaction.replace(R.id.root_frame_layout, new MatchingFashionFragment());        fragmentTransaction.commit();        return view;    }}

当这个Fragment对象被嵌入到一个Activity中然后又被其他Fragment取代后,然后这个Fragment对象又被重新放回到Activity中时,在fragmentTransaction.commit();处会报如下的错误

java.lang.IllegalStateException: Activity has been destroyed            at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1365)            at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)            at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)            at com.jd.wxsq.app.Fragment.MatchFragment.onCreateView(MatchFragment.java:70)            at android.support.v4.app.Fragment.performCreateView(Fragment.java:1500)            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:927)            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)            at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)            at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1467)            at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440)            at android.os.Handler.handleCallback(Handler.java:733)            at android.os.Handler.dispatchMessage(Handler.java:95)            at android.os.Looper.loop(Looper.java:136)            at android.app.ActivityThread.main(ActivityThread.java:5017)            at java.lang.reflect.Method.invokeNative(Native Method)            at java.lang.reflect.Method.invoke(Method.java:515)            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)            at dalvik.system.NativeStart.main(Native Method)

问题原因分析

查看android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1365)处的源码:

    public void enqueueAction(Runnable action, boolean allowStateLoss) {        if (!allowStateLoss) {            checkStateLoss();        }        synchronized (this) {            if (mDestroyed || mActivity == null) {                throw new IllegalStateException("Activity has been destroyed");            }            if (mPendingActions == null) {                mPendingActions = new ArrayList();            }            mPendingActions.add(action);            if (mPendingActions.size() == 1) {                mActivity.mHandler.removeCallbacks(mExecCommit);                mActivity.mHandler.post(mExecCommit);            }        }    }

在第7行,可以看到mActivity为null了,所以可以猜测Fragment被detach后,Fragment的mChildFragmentManager的mActivity变为空了,而Fragment被attach后,mChildFragmentManager的mActivity又没有被正确的赋予Activity的对象,才造成了这个bug

在哪里被赋值成null呢?请看下面的代码
C:\Users\lihuaping\AppData\Local\Android\sdk\android-sdk\extras\android\m2repository\com\android\support\support-v4\19.0.0\support-v4-19.0.0-sources.jar!\android\support\v4\app\FragmentManager.java

    public void dispatchDestroy() {        mDestroyed = true;        execPendingActions();        moveToState(Fragment.INITIALIZING, false);        mActivity = null;        mContainer = null;        mParent = null;    }

所以我们要做的就是,在Fragment被detach时,把mChildFragmentManager置空就可以了,mChildFragmentManager是Fragment的私有成员,如何做到?使用反射就可以做到
在你的Fragment的代码中加入如下的代码:

    @Override    public void onDetach() {        super.onDetach();        try {            Field childFragmentManager =                    Fragment.class.getDeclaredField("mChildFragmentManager");            childFragmentManager.setAccessible(true);            childFragmentManager.set(this, null);        } catch (NoSuchFieldException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }    }

更多相关文章

  1. mybatisplus的坑 insert标签insert into select无参数问题的解决
  2. 类和 Json对象
  3. android调用本地录制程序获取录制文件路径的问题
  4. Android(安卓)WebView 加载网页遇到的问题
  5. Android语音识别
  6. Android之SharedPreference轻量级数据存储
  7. Android之merge(二)
  8. android 顶部的通知栏
  9. 【Android】串口通信

随机推荐

  1. Ubuntu下搭建Android(安卓)NDK开发环境
  2. android设置Activity背景透明
  3. Android(安卓)启动过程分析 (二)
  4. 如何让android apk 获得系统权限
  5. Android(安卓)SearchView详细使用
  6. android开发每日汇总【2011-10-27】
  7. 【Android学习入门】Android中activity的
  8. 【收藏】android WebView总结
  9. Android:ImageView如何显示网络图片
  10. Android20_广播机制(一)