安卓应用和Activity的生命周期

安卓应用和Activity的生命周期

凡是前端组件化的地方,都要折腾生命周期,Vue,React连同Android都跑不了......

很多人都关注手机性能的提升,认为相比与桌面计算系统,手机的计算性能有了很大的进步,不过实际上移动设备的性能或者说资源依然被认为很有限(当然了,功率才几瓦,算力能有多高),尤其是内存的使用方面.所以安卓操作系统的一个关键任务,就是如何将有限的资源分配给操作系统和应用程序,让这些内容都能够及时对用户的操作作出反应.为了达到这个目的,不管是整个应用,还是应用中的组件,都有着生命周期管理.

安卓开发的关键之一,就是要理解应用和Activity的生命周期模型,以及在应用运行过程中,如何对状态的改变产生响应.

安卓进程的状态

在一个安卓进程里,这个进程的状态由这个进程里最高级别的活动组件的优先级来决定,一个进程可以有五种状态之一:

  1. Foreground Process, 最高优先级
  2. VisibleProcess
  3. Service Process
  4. Background Process
  5. Empty Process, 最低优先级

来一个一个看一下

Foreground Process

我翻译成前台进程,是最高优先级的进程,一般同时只有一到二个前台进程,也是最不可能被系统杀掉的进程.一般来说前台进程的条件是:

  1. 拥有正在和用户交互的内容
  2. 拥有与用户交互内容相关联的服务
  3. 有一个调用过startForeground()方法的服务,如果终止会影响用户交互
  4. 拥有一个正在执行onCreate() onResume()或者onStart()回调方法的服务
  5. 拥有一个正在执行onReceive()方法的Broadcast Receiver

可以看出,前台进程基本上都是与当下用户交互相关联的内容,肯定会被系统给予最优先的资源,这样才不会让手机看上去比较"卡".

VisibleProcess

拥有可以让用户看到的内容,但是没有和用户发生交互,就是可见进程,比如切换应用的页面,半屏幕的对话框等.与可见进程有关联的服务也被判断为可见进程.

Service Process

拥有已经启动的服务的进程,被分类为此类别.

Background Process

拥有对用户不可见的Acitivity,但是不拥有任何服务.被分类到这个下边的进程,有很高的可能性被系统关闭,释放出内存给其他更高优先级的进程使用.ART有一个后台进程的列表,根据使用频度和系统压力,会选择关闭其中的一些进程.

Empty Process

空进程不包含任何内容,只在内存中等着在其中装入新的应用程序,所以是最低等级的进程.

在实际中,由于出现进程间互相依赖的情况,判断方法不是这么简单,操作系统的进程调度一直都是操作系统最核心也最复杂的内容之一.不过安卓文档里有一条规范,就是一个进程的优先度,不能低于它为之服务的另外一个进程(否则会造成被服务对象还没结束,其依赖的提供服务对象就结束了,导致程序无法运行).

Activity的生命周期

由于一个应用程序的主要组成部分就是各个Activity,而应用程序的进程优先级又是由其中的Activity所决定的,所以了解Activity的生命周期就非常关键了.

在应用程序运行的时候,其中的各个Activity会反复被用户使用,系统对于每个应用,使用一个Activity Stack,一个栈来管理这些Acitivity.

Activity Stack

对于每个运行中的应用,操作系统会为其维护一个栈,当一个应用程序开始运行的时候,它的第一个Activity就会被放入这个栈中,第二个Activity打开的时候,会继续被压入栈中,栈顶的始终是当前活动的Activity,当一个Activity终止的时候,会被弹出,其下边的一个Activity就会变成当前的活动栈.就和浏览器维护的历史记录很像,弹出栈的Activity会被销毁来释放内存空间.

此外,当资源出现问题的时候,操作系统也会把一些最老的栈清除掉.书上的图不错:
activity stack

Activity的状态

有四种状态:

  1. Active/Running,这表示Activity处在栈顶端,正在和用户交互,当前应用是前台应用状态.这也是最不可能被系统干掉的情况.
  2. Paused,这个对用户可见,但不是处于活动状态,这种状态的Activity依然处于内存中,并且其维护的数据也会依然可用,方便快速恢复到Active状态.
  3. Stopped,对用户不可见,和暂停的Activity一样,也保有对应的状态和数据,然而被系统干掉的风险更高
  4. Killed,被ART干掉了,如果想再次运行,就要经历完整的重新启动应用的过程.

导致Activity状态发生变化的原因

有三种:

  1. 将这个Activity在前后台移动,比如切换到另外一个程序或者页面
  2. 关闭Activity
  3. 系统配置发生变更(比如手机从横屏变成竖屏)

一般来说,凡是会导致Activity的界面发生变化的配置,都会导致系统先销毁原来的Activity,再重新创建,这是因为相比其他手段,这个手段最高效.当然,也有一些配置改变并不会导致Activity发生变化,这个时候就不一定需要重新来一遍.

处理状态变化

处理状态变化有两种方式:

  1. 在系统调用的生命周期方法里编写处理状态的代码.像之前的onCreate()方法,在特定的时候会被ART调用,只要在其中写上处理状态的代码,在Activity到某个状态的时候,其中的处理状态变化的代码就会被调用.这也是比较传统的做法.
  2. Google引入的新方法, 使用Jetpack Android Architecture
    中提供的涉及到生命周期的类.这个我现在还不清楚书上说的是什么意思.

为什么要管理生命周期,其实主要是用来处理状态(state)变化,所谓状态,其实是指的程序依赖的数据.在一个Activity的状态发生变化的时候,很可能其依赖的数据也发生了变化,最简单比如一个需要登录的app,在切换Activity的时候,就要在状态从活动和其他状态切换的时候,检测用户是否还在登录状态,如果不是,则不能将那些负责登录后功能的Activity展示给用户,这个逻辑一般就要写在声明周期方法中.说白了,就和web应用中的有状态组件很类似.

处理生命周期状态变化

这里只来看传统的方法,虽然上边提到了新的方法,但其实很多代码还是使用传统的方法,而且传统的方法对于理解状态变化更深刻,所以还是要深刻掌握的.

ActivityFragment的生命周期方法

Activity为例,在之前的例子里,代码中可以直接看到MainActivity继承的是AppCompatActivity,继续探究下去,整个继承关系如下:

  1. `MainActivity
  2. AppCompatActivity
  3. FragmentActivity
  4. ComponentActivity
  5. androidx.core.app.ComponentActivity
  6. Activity

最下边的Activity以及上边的所有类,都实现了若干方法,比如onCreate(),这些特定的方法,会在生命周期的不同时刻被ART调用.Fragment类也是如此.我们编写的类想要针对生命周期进行响应的时候,需要重写对应的方法.现在就来看一下具体的方法.

onCreate(Bundle savedInstanceState)

Activity第一次被创建,一些对应的初始化工作完成之后,会调用这个方法,调用这个方法时,Activity在内存中被创建,但还没有显示到屏幕上.这个方法的参数是从调用者传入的一个Bundle对象,这个对象一般会含有动态的状态信息,一般和用户界面相关.

onRestart()

在之前处于Stopped状态,要重新启动的时候,调用该方法.

onStart()

总是在onCreate()onRestart()调用完后立刻调用,调用这个说明界面已经准备好对用户可见.

onResume()

onStart()调用之后, 如果Activity进入栈顶要展示给用户,就会调用这个方法.

onStop()

onStop()调用之后, 如果Activity不位于栈顶,则会调用此方法,此时Activity对用户不可见.这个方法之后要么是onRestart(),要么是onDestroy().

onPause()

调用这个方法意味着Activity暂停,所以一些耗时长,重型的方法不要写在这里.
这个方法之后可以接onResume(),表示重新位于前台,也可能是onStop(),即停止.

onDestroy()

Activity要被销毁.一般来说一个页面如果执行了finish()方法,ART就会打算将其销毁,从而调用此方法.注意并不是一个Activity工作结束就一定会调用该方法.

以下是fragment特有的方法

onAttach()

当一个fragment附加到Activity上时候调用

onCreateView()

创建并返回一个fragment的用户界面的时候调用

onActivityCreated()

fragment附加到的ActivityonCreate()方法执行完毕之后会调用这个方法.

onViewStatusRestored()

fragment保存的视图继承恢复的时候(我没看懂是什么意思)

和状态有关的方法

除了生命周期方法之外,还需要了解两个和应用状态关系密切的方法

onRestoreInstanceState(Bundle savedInstanceState)

这个方法会在onStart()执行被调用,一般会在Activity从之前的状态恢复的时候使用,用来读取之前的数据,也常用做初始化Acitivity数据的手段.

onSaveInstanceState(Bundle outState)

Activity被销毁之前调用,常用来保存这个应用所需的数据.所以可以看到,直接销毁一个应用,这个应用也还是有机会做一些事情的.当应用重新启动的时候,这个函数的参数会传递给onCreate()onRestoreInstanceState().

在重写这两个方法的时候,一定要记住,必须首先调用一下super的同名方法,否则会报运行时错误.说了半天,还是上一张图最清晰:
activity-life-cycle

LICENSED UNDER CC BY-NC-SA 4.0
Comment