Activity结合Fragment生命周期的全面测试;Fragment not attached to Activity问题解析

来源:互联网 发布:淘宝二手ps4哪家好 编辑:程序博客网 时间:2024/06/16 14:41

Activity结合Fragment生命周期的全面测试;Fragment not attached to Activity问题解析

最近的一个项目中出现以下问题,用instant run快速重启应用时总是报Fragment not attached to Activity异常,由于目赶工没时间做其他测试,自己感觉也问题不大就暂时没去管他。这几天有时间解决一下。

   其实一出现这个问题心里大概有个数是什么原因导致的苦于不知道具体原理和症结,对于程序从启动到结束的具体流程不熟悉。

该异常,是因为Fragment的还没有Attach到Activity时,调用了如getResource()、getString()等,需要上下文Content的函数。原因就是这么个原因解决办法也是找到一些其中就有加isAdded()判断,如果你知道具体那一步会出现这个问题的话确实可以解决,但是不能因为问题解决了而不去先其中的深层次问题。比如为什么fragment会出现未和acticity关联的问题?fragment在activity,运行时他们的各自生命周期是怎么走的,相信搞明白这些,这个问题也就不是问题可以从多方面去解决。从以下几个方面一起学习学习:

Activity生命周期

参考文档

生命周期图就不上了完善一大堆。一个一个来解析:

  1. onCreate:创建activity的时候调用此方法,我们一般情况会在此方法中,做一些数据初始化的工作,例如:加载布局,创建线程等等。

  2. onStart:在activity从不可见到可见的时候回调此方法。

  3. onRestart():表示activity正在重新启动。出现的时机是activity的onPause和onStop执行了,接着用户又回到这个activity时。activity重新变为可见状态的时候,即重新切到前台回调此方法。

  4. onResume:activity获取焦点的时候回调此方法,在此方法中可进行一些与界面相关的操作。

  5. onPause:界面失去焦点的时候回调此方法对用户来说,界面变为不可触,我们在这个方法中做一些数据保存的工作表示,activity正在停止工作,紧接着会执行onStop。这里不可以执行耗时操作。因为当前activity的onPause执行完,下一个activity的onResume才会执行。

  6. onStop:表示activity的停止工作。activity变为不可见的时候回调此方法,可以执行一些耗时操作。

  7. onDestory:activity从内存中回收时调用此方法,我们一般在这个方法中做一些释放内存的工作,将全局变量指向null表示activity的销毁。

Fargment生命周期

参考文档

  1. onAttach():回调获得activity的传递值,这个时候fragment和activity建立了关联,一般可以通过getActivity()获得依附的activity。他只调用一次。为什么是一般呢,因为有的时候activity会意外销毁,这个时候如果程序中有耗时操作如网络请求,线程还在执行但是此时获得不到上下文会报空指针。我的问题就是因为这个空指针导致:(网络请求后获得数据渲染数据用到了上下文,如果这个时候突然重启activity就导致了fragment调用了两次生命周期,第一次调用后紧接着第二次,两次都会开启线程网络请求第一次是获取不到数据的会返回失败,而我在返回失败是用了土司,这时候fragment还没atach到activity所以报not attached to Activity异常)

  2. onCreate():系统创建fragment的时候回调他,在他里面实例化一些变量这些个变量主要是:当你停止的时候你想保持的数据。他也只调用一次。

  3. onCreateView():第一次使用的时候fragment会在这上面画一个Layout出来,要返回一个布局的View,也可以返回null,当系统用到fragment的时候fragment就要返回他的view,越快越好,所以尽量在这里不要做耗时操作,当然线程还是可以的。说白了就是加载fragment的布局的。一般会先判断是否为null。

  4. onActivityCreated()
    当Activity中的onCreate方法执行完后调用。
    所以不要再onCreateView()中进行 与activity有交互的UI操作,UI交互操作可以在onActivityCreated()里面进行。所以呢:这个方法主要是初始化那些你需要你的父Activity或者Fragment的UI已经被完整初始化才能初始化的元素。如果在onCreateView里面初始化空间 会慢很多,比listview等。

  5. onStart():同activity。Fragement 启动时回调, 此时Fragement可见。

  6. onResume():同activity。在activity中运行是可见的激活Fragement 进入前台, 可获取焦点时激活。

  7. onPause():同activity。其他的activity获得焦点,这个仍然可见:
    指的是用户离开这个fragment(并不是被销毁)。

  8. onStop():同activity。fragment不可见的,可能情况:activity被stopped了或fragment被移除但被加入到回退栈中一个stopped的fragment仍然是活着的如果长时间不用也会被移除。

  9. onDestroyView():Fragment中的布局被移除时调用,表示fragemnt销毁相关联的UI布局清除所有跟视图相关的资源。
    用处:ViewPager+Fragment,由于ViewPager的缓存机制,每次都会加载3页。例如:有四个fragment 滑动到第四页的时候 第一页执行onDestroyView(),但没有执行onDestroy。他依然和activity关联。当在滑动到第一页的时候又执行了onCreateView(),会出现重复加载view的局面,解决方法自行百度。。

  10. onDestroy():同activity。销毁fragment对象。

  11. onDetach():Fragment和Activity解除关联的时候调用脱离activity。


测试代码

Activity:

@Override    protected void onCreate(Bundle savedInstanceState) {        Log.d("fty", "onCreate: " +"start");        super.onCreate(savedInstanceState);        Log.d("fty", "onCreate: " +"end");        setContentView(R.layout.activity_home);        FrameLayout container = (FrameLayout) findViewById(R.id.container);        TextView textView = (TextView) findViewById(R.id.tv);        textView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                recreate();            }        });        FragmentManager fragmentManager = getSupportFragmentManager();        FragmentTransaction ft = fragmentManager.beginTransaction();        ft.add(R.id.container,PlusOneFragment.newInstance()).commit();    }    @Override    protected void onStart() {        Log.d("fty", "onStart: " + "start");        super.onStart();        Log.d("fty", "onStart: " + "end");    }    @Override    protected void onResume() {        Log.d("fty", "onResume: " + "start");        super.onResume();        Log.d("fty", "onResume: " + "end");    }    @Override    protected void onPause() {        Log.d("fty", "onPause: " + "start");        super.onPause();        Log.d("fty", "onPause: " + "end");    }    @Override    protected void onStop() {        Log.d("fty", "onStop: " + "start");        super.onStop();        Log.d("fty", "onStop: " + "end");    }    @Override    protected void onDestroy() {        Log.d("fty", "onDestroy: " + "start");        super.onDestroy();        Log.d("fty", "onDestroy: " + "end");    }

Fragment:

@Override    public void onAttach(Context context) {        Log.e("fty", "onAttach: " + "start");        super.onAttach(context);        Log.e("fty", "onAttach: " + "end");    }    @Override    public void onCreate(Bundle savedInstanceState) {        Log.e("fty", "onCreate: " + "start");        super.onCreate(savedInstanceState);        Log.e("fty", "onCreate: " + "end");    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        Log.e("fty", "onCreateView: " + "start");        View view = inflater.inflate(R.layout.fragment_plus_one, container, false);        TextView textView = (TextView) view.findViewById(R.id.tv);        Log.e("fty", "onCreateView: " + "end");        return view;    }    @Override    public void onActivityCreated(@Nullable Bundle savedInstanceState) {        Log.e("fty", "onActivityCreated: " + "start");        super.onActivityCreated(savedInstanceState);        Log.e("fty", "onActivityCreated: " + "end");    }    @Override    public void onStart() {        Log.e("fty", "onStart: " + "start");        super.onStart();        Log.e("fty", "onStart: " + "end");    }    @Override    public void onResume() {        Log.e("fty", "onResume: " + "start");        super.onResume();        Log.e("fty", "onResume: " + "end");    }    @Override    public void onPause() {        Log.e("fty", "onPause: " + "start");        super.onPause();        Log.e("fty", "onPause: " + "end");    }    @Override    public void onStop() {        Log.e("fty", "onStop: " + "start");        super.onStop();        Log.e("fty", "onStop: " + "end");    }    @Override    public void onDestroyView() {        Log.e("fty", "onDestroyView: " + "start");        super.onDestroyView();        Log.e("fty", "onDestroyView: " + "end");    }    @Override    public void onDestroy() {        Log.e("fty", "onDestroy: " + "start");        super.onDestroy();        Log.e("fty", "onDestroy: " + "end");    }    @Override    public void onDetach() {        Log.e("fty", "onDetach: " + "start");        super.onDetach();        Log.e("fty", "onDetach: " + "end");    }

测试结果

启动时候的生命周期:

启动时候的生命周期

重启activity时的生命周期:

重启activity时的生命周期图1
重启activity时的生命周期图2


总结

由重启activity的生命周期中可以看出activity的onCreate()开始执行还没结束的时候Fragment的onAtach()和onCreate()已经开始执行并执行完毕,之后Fragment执行第一次onCreateView()此时代码中是获取不到上下文的,但第二次执行onCreateView()时才能获取到上下文。所以如果在onCreateView()中有线程进行耗时操作并且有用到上下文的的话,当重启activity的时候第一次就获取不到上下文报空指针。

阅读全文
0 0
原创粉丝点击