Activity重建之殇

Activity重建之殇

很多时候,对于一些初学者来说,activity的重建是很痛苦的,面对网络上众多的说法,我们无从下手,无从做起。

其实很多时候只要我们掌握了其中的必要方法,就能解决大部分的activity的重建问题。下面我就来总结一下activity重建的一些必要方法,以及列举几点常见的问题。

1. Activity何时需要重建

activity的销毁:

正常:正常情况下的销毁,比如用户按下Back按钮或者是activity自己调用了finish()方法

异常:异常情况下的销毁,或者出现内存不足的情况下而销毁。简单来说就是在“未经许可”的情况下被销毁了

异常销毁后,Activity会重新创建一个新的对象,而不再是以前的Activity

重建后是新对象

新对象

2. 如何重建

onSaveInstanceState()方法的覆写

为什么?

Android应用框架中定义的几乎所有UI控件都恰当的实现了onSaveInstanceState()方法, 因此当activity被摧毁和重建时, 这些UI控件会自动保存和恢复状态数据

但是很多时候我们需要保存更多的数据才能满足我们的重建,这时候我们就可以覆写onSaveInstanceState()方法保存一些保存瞬态数据,比如成员变量等。

当Activity在非正常情况下销毁时,会在onPause或onStop方法之前调用onSaveInstanceState方法,正常情况下不会调用

@Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("testStr", mString);
        outState.putInt("testInt", mInt);
    }

恢复Activity的状态

当Activity被销毁后要重建时,可以从onSaveInstanceState方法中保存的Bundle对象中恢复数据。onCreate()和onRestoreInstanceState()两个方法的Bundle对象保存的数据是一样的。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) {
            mString = savedInstanceState.getString("testStr");
            mInt = savedInstanceState.getInt("testInt");
        }
    }

或者使用onRestoreInstanceState,只有在Activity重建恢复数据时才会调用onRestoreInstanceState方法,正常情况下不会调用,所以不需要判断Bundle是否为空

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        mString = savedInstanceState.getString("testStr");
        mInt = savedInstanceState.getInt("testInt");
    }

3. Fragment如何重建

Fragment重建跟Activity重建大同小异,方法差不多,下面是我在Fragment重建过程中遇到的一些问题:

  1. Activity销毁前hide的Fragment在重建之后全部出现

    原因:
    经过项目应用跟自己写的demo测试发现,在Activity销毁之前hide到栈中的Fragment在重建之后mHidden全部为false,也就是说隐藏的Fragment不再隐藏,所以我们就看到了全部展现出来的样子
    解决办法:
    通过Activity或者其所在的父Fragment管理控制Fragment隐藏,但由于无法知道Activity重建时Fragment何时重建好,所以目前的做法是在Activity中监听Fragment是否重建好了

回调接口

隐藏fragment

  1. Fragment重建之后出现重叠(出现两个相同的Fragment)

    原因:
    由于Activity重建的几率比较小,所以很多开发者可能不会注意到Fragment重建后出现的问题。一般情况下,Fragment的创建都是在Activity的onCreate或onStart里面,当Activity重建时导致再次创建了Fragment,而重建的Fragment也出现了,所以就出现了重叠。

    解决办法:
    复用重建的Fragment或者删掉重建的重新创建:

复用fragment

  1. 重建的Fragment上面的item无法点击

    原因:
    原因很简单,如果listener是从别的地方传进来的,当Fragment重建时如果没有保存listener,必然的会无法监听点击事件

    解决办法:
    目前想到的方法有两种:

    1. 在前面所说的那个监听Fragment重建完成的回调里传listener进去
    2. 在onAttach方法里面把Activity强制转化为listener

转化为listener

  1. 重建的特殊的Fragment状态异常

    原因:
    提出这个状态异常主要是针对项目里遇到的滑块无法滑动的问题。原因是Fragment重建时需要重新走一遍onBindViewHolder,所以通过findViewHolderAdaterByPosition是无法找到数据的

    解决办法:
    通过前面说的onSaveInstanceState方法保存position,在onBindViewHolder时恢复状态

4. 建议及注意事项

一般情况下很难复现Activity销毁的情况,如果我们要测试可以通过开启“不保留活动”,如图:

不保留活动

如果不需要重建Activity或者Activity里面装载的Fragment比较多,要恢复到原来的状态比较困难,可以重写Activity或Fragment的onSaveInstanceState方法,如图:

不恢复

5. Commit与commitAllowingStateLoss的区别:

在这里我觉得还有必要补充一下commit和commitAllowingStateLoss的区别:

commit方法和commitAllowingStateLoss方法,都同时调用了commitInternal方法,只是传的参数略有不同

区别

在对 commit和commitAllowingStateLoss的传参进行判断后,将任务扔进activity的线程队列中。这个两个方法区别就在传参判断后的处理方法checkStateLoss

这里写图片描述

当使用commit方法时,系统将进行状态判断,如果状态(mStateSaved)已经保存,将发生”Can not perform this action after onSaveInstanceState”错误。如果mNoTransactionsBecause已经存在,将发生”Can not perform this action inside of ” + mNoTransactionsBecause错误

这里写图片描述

避免异常抛出的最优方法就是避免在异步回调方法中调用commit

这里写图片描述

以上就是我对activity重建的一些见解,希望对大家有帮助,如有写得不对的地方,欢迎指出。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值