四大组件之Activity 第3节 Activity的系统回收

更新时间 修改意见
2016-08-02 陈敏

第3节 Activity的系统回收

在Activity生命的周期中,安卓系统可能直接回收Activity。系统回收Activity有两种常见的情况,

  1. 系统资源紧张;
  2. 屏幕的旋转;

3.1 资源紧张

当系统资源紧张时,例如你打开了很多应用,系统中的可用内存很少了。这时安卓系统会采用一定的策略来回收系统中的资源,这些资源包括前台可见的Activity、后台不可见的Activity,后台中运行的Service,在状态栏中给出了“正在运行”的提示的Service等等。

在回收资源的时候,系统会根据这些资源所在的进程优先级来判断。进程优先级高的,最后回收;进程优先级低的,最先回收。 这些进程优先级从高到低分别是,

  • 前台优先级-IMPORTANCE_FOREGROUND,它可能是,

    • 一个正在与用户进行交互的Activity;

    • 一个被Activity绑定的Service,而这个Activity正在与用户进行交互;

    • 一个被调用了startForground()方法的Service,此时它的优先级被设置成了前台优先级;

    • 一个正在经历周期变化的Service(也就是说这个Service的onCreate() onDestroy()等周期变化的方法正在被触发调用);

    • 一个正在执行onReceive()BroadcastReceiver

  • 可见优先级-IMPORTANCE_VISIBLE,它可能是,

    • 一个虽然用户不能交互、但是用户仍然能看到的Activity;

    • 一个绑定了可见Activity的Service;

  • 服务优先级-IMPORTANCE_SERVICE,它可能是,

    • 一个普通的Service(没有处于前台优先级和可见优先级中那些Service的状态);
  • 后台优先级-IMPORTANCE_BACKGROUND,它可能是,

    • 不可见的Activity;
  • 空优先级-IMPORTANCE_EMPTY,

    • 它当中没有任何应用组件,它只是为了提高应用的启动速度而预留的空进程,可以随时被系统回收。

这里举个例子,资源极度匮乏的时候,

  1. 系统会优先回收那些没有显示的Activity(例如在onStop()状态下的Activity);
  2. 如果回收那些资源以后,发现资源还是不够用,就会回收虽然显示了、但却没有和用户做交互的Activity(例如在onPause()状态下的)。

这里会遇到一个问题:假如Activity A启动了Activity B之后,系统发现内存不足,在回收了其它所有资源后,它不得不继续回收Activity A。

3.1.1 产生的问题

此时与Acitity B正在交互的用户,点击了“返回”按钮,按照道理,应该显示Activity A才对,但是系统已经回收了Activity A。这时该怎么办呢?

系统遇到这种情况就会重新创建Activity A,重新调用它的onCreate()。

不过这里又会遇到另一个很现实的问题:如果之前的Activity A上面用户正输入了一些东西,例如他的名字和邮箱地址,或者是已经编辑了很长一大段的文字,如果系统onCreate的话,这些输入的东西就会被清除掉了。这可怎么办呢?

3.1.2 解决办法

安卓系统为我们提供了一个这种情况下数据的重建机制:在Activity被放到后台运行的时候使用onSaveInstanceState()回调函数来保存这些数据,

在Activity被重建的时候,使用onRestoreInstanceState()回调函数来恢复这些数据

需要注意的是,onSaveInstanceState()onRestoreInstanceState()在Activity周期切换过程中并不一定会被调用,只是在这种Activity异常流程处理时(Activity被系统回收、config信息变化等情况),才会被调用到。

3.2 屏幕旋转

屏幕旋转时,Activity的生命周期也将发生变化。

如果一个Activity从创建出来,到显示,然后旋转,那么它将经历:
onCreate()->
onStart()->
onResume()->
用户可以与Activity交互,此时屏幕进行旋转,从竖屏变横屏->
onPause()->
onSaveInstanceState()->
onStop()->
onDestroy()->
onCreate()->
onStart()->
onRestoreInstanceState()->
onResume()->
用户可以与Activity交互;

可以看到,旋转的时候onCreate()函数会被再次调用。在这里,如果拥有横屏布局文件,onCreate()中的setContentView()将会使用横屏的布局,如果没有,依然使用默认的布局文件。

3.2.1 产生的问题

如果Activity从竖屏变成横屏,那么会先执行onDestroy(),再进行一次onCreate()创建的过程。这意味着之前界面上显示的数据需要重新刷新一次。

假如之前刷新这些数据需要花费很长的时间,那就有必要认真的思考如何避免数据的再次刷新。

3.2.2 解决方法

解决屏幕旋转时Activity被create两次的方法有两种。

  1. onSaveInstanceState()onRestoreInstanceState()可用用来保存和还原这些数据;

  2. AndroidManifest.xml文件中,给这个Activity组件加上android:screenOrientation="orientation|screenSize"的属性就可以了;

    这种Activity从创建出来,到显示,然后旋转,那么它将经历:
    onCreate()->
    onStart()->
    onResume()->
    用户可以与Activity交互,此时屏幕进行旋转,从竖屏变横屏->
    onConfigurationChanged();

    在被触发的onConfigurationChanged()函数中,可以感知到屏幕的变化,

    如此一来,这个Activity在旋转时就不会重走销毁、创建的过程了,而只是在旋转后经历一个onConfigurationChanged()。这种情况下,即使它存在横屏布局文件,这个横屏布局也不会被使用到,因为onCreate()并没有被调用到,也就不会调用setContentView)了。


/**************************************************************************/
* 版权声明
* 本教程只在CSDN安豆网发布,其他网站出现本教程均属侵权。
/
**************************************************************************/