Activity的生命周期和启动模式

目录

  • Activity生命周期全面分析
  • Activity的启动模式
  • Intent的匹配规则

Activity生命周期全面分析

典型情况是指用户参与的情况下,Activity所经过的生命周期的变化;

异常情况是指Activity被系统回收或者由于当前设备的Configuration发生改变从而导致Activity被销毁重建。

典型情况下的生命周期分析

onCreate:表示Activity正在被创建,这是生命周期的第一个方法,在这个方法中,我们可以做一些初始化的工作,比如调用onContentView去加载界面布局资源,初始化Activity所需数据等。

onRestart:表示Activity正在重新启动,一般情况下,当当前Activity从不可见重新变为可见时,onRestart就会被调用,这总情况一般是用户行为所导致的,比如用户按home键切换到桌面或者用户打开了一个新的Activity,这时当前的Activity就会被暂停,也就是onPause和onStop方法被执行了,接着用户又回到了这个Activity,就会出现这种情况。

onStart:表示Activity正在被启动,即将开始,这个时候Activity已经可见了,但是还没有出现在前台,还无法和用户交互,这个时候我们可以理解为Activity已经启动了,但是我们还没有看见。

onResume:表示Activity已经可见了,并且出现在前台,并开始活动了,要注意这个和onStart的对比,这两个都表示Activity已经可见了,但是onStart的时候Activity还处于后台,onResume的时候Activity才显示到前台。

onPause:表示Activity正在停止,正常情况下,紧接着onStop就会被调用,在特殊情况下,如果这个时候再快速的回到当前Activity,那么onResume就会被调用。此时可以做一些数据存储,停止动画等工作,但是注意不要太耗时了,因为这样会影响到新的Activity的显示,onPause必须先执行完,新Activity的onResume才会执行。

onStop:表示Activity即将停止,同样可以做一些轻量级的资源回收,但是不要太耗时了。

onDestroy:表示Activity即将被销毁,这是Activity生命周期的最后一个回调,在这里我们可以做一些最后的回收工作和资源释放。

Activity的生命周期和启动模式_第1张图片
Activity生命周期的切换过程

具体场景说明:

1.针对一个特定的Activity,第一次启动,回调如下:onCreate ——> onStart ——> onResume。

2.当用户打开新的Activity或者切换到桌面的时候,回调如下:onPause ——> onStop ——> 这里有一种特殊的情况就是,如果新的Activity采取了透明的主题的话,那么当前Activity不会回调onStop。

3.当用户再次回到原来的Activity,回调如下:onRestart ——> onStart ——> onResume。

4.当用户按back键的时候回调如下:onPause ———> onStop ——> onDestroy。

5.当Activity被系统回收的时候再次打开,生命周期回调方法和1是一样的,但是你要注意一下就是只是生命周期一样,不代表所有的进程都是一样的,这个问题等下回详细分析。

6.从整个生命周期来说,onCreate和onDestroy是配套的,分别标示着Activity的创建和销毁,并且只可能有一次调用,从Activity是否可见来说,onStart和onStop是配套的,随着用户的操作和设备屏幕的点亮和熄灭,这两个方法可能被调用多次,从Activity是否在前台来说,onResume和onPause是配套的,随着用户操作或者设备的点亮和熄灭,这两个方法可能被多次调用。

这里提出两个问题:

1.onStart和onResume,onPause和onStop从描述上都差不多,对我们来说有什么实质性的不同呢?

答:onStart和onStop是从Activity是否可见这个角度来回调的,而onResume和onPause是从Activity是否位于前台这个角度来回调的,除了这种区别,在实际的使用中,没有其他明显的区别。

2.假设当前Activity为A,如果用户打开了一个新的Activity为B,那么B的onResume和A的onPause谁先执行尼?

答:当新的Activity启动的时候,旧的Activity的onPause方法会先执行,然后才启动新的Activity。也就是说,不能在onPause中做重量级的操作,因为必须在onPause执行完成以后新的Activity才能Resume。

异常情况下的生命周期分析

1.情况1:资源相关的系统配置发生改变导致Activity被杀死并重新创建

比如当前Activity处于竖屏,我们突然旋转屏幕,由于系统配置发生了改变,在默认情况下,Activity会被销毁并且重新创建,当然我们也可以阻止系统重新创建我们的Activity。

默认情况下,如果我们的Activity不做特殊处理,那么当系统配置发生改变之后,Activity就会销毁并且重新创建,可以看图:

Activity的生命周期和启动模式_第2张图片
异常情况下Activity的重建过程

当系统配置发生改变的时候,Activity会被销毁,其onPause,onStop,onDestroy均会被调用,同时由于Activity是异常情况下终止的,系统会调用onSaveInstanceState来保存当前Activity的状态,这个方法调用的时机是在onStop之前,他和onPause没有既定的时序关系,他即可能在onPause之前调用,也有可能在之后调用。

当我们onSaveInstanceState保存到Bundler对象作为参数传递给onRestoreInstanceState和onCreate方法,因此我们可以通过onRestoreInstanceState和onCreate方法来判断Activity是否被重建。如果被重建了,我们就取出之前的数据恢复,从时序上来说,onRestoreInstanceState的调用时机应该在onStart之后。

这里可以简单的这么理解,系统只在Activity异常终止的情况下才会调用onSaveInstanceState和onRestoreInstanceState来存储和恢复数据,其他情况不会触发。

2.情况2:资源内存不足导致低优先级的Activity被杀死

Activity按照优先级的从高往低,可以分为三种:

  1. 前台Activity:正在和用户交互的Activity,优先级最高。
  2. 可见但非前台Activity:比如对话框,导致Activity可见但是位于后台无法和用户直接交互。
  3. 后台Activity:已经被暂停的Activity,比如执行了onStop,优先级最低。

当系统内存不足的时候,系统就会按照上述优先级去杀死目标Activity所在的进程,并且在后续通过onSaveInstanceState和onRestoreInstanceState来存储和恢复数据。

Activity的启动模式

Activity的LaunchMode

standard

standard:标准模式,这也是系统的默认模式,每次启动一个Activity都会重新创建一个实例,是否这个实例已经存在。在这种模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的Activity所在的栈内。

当我们用ApplicationContext去启动standard模式的Activity的时候就会报错,因为我们的standard模式的Activity默认会进入启动它的Activity所属的任务栈中,但是由于非Activity类型的Context(如ApplicationContext)并没有所谓的任务栈,所以这就有问题了,解决这个问题,就是待启动Activity指定FLAG_ACTIVITY_TASK标记位,这样启动的时候就会为他创建一个新的任务栈,这个时候待启动Activity实际上是以singleTask模式启动的。

singleTop

singleTop:栈顶复用模式,在这个模式下,如果新的Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时他的onNewIntent方法会被调用,通过此方法的参数我们可以取出当前请求的信息,需要注意的是,这个Activity的onCreate,onStart不会被系统调用,因为他并没有发生改变。

singTask

singTask:栈内复用模式,这是一种单实例模式,在这种模式下,只要Activity在一个栈内存在,那么多次启动此Activity都不会创建实例,和singTop一样,系统也会回调其onNewIntent方法。

singleInstance

singleInstance:单实例模式,这是一种加强的singleTask的模式,他除了具有singleTask的所有属性之外,还加强了一点,那就是具有此模式下的Activity只能单独的处于一个任务栈中,换句话说,比如ActivityA是singleInstance模式,当A启动的时候,系统会为创建创建一个新的任务栈,然后A独立在这个任务栈中,由于栈内复用的特性,后续的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了。

如何给Activity指定启动模式?

有两种方法,第一种是通过清单文件为Activity指定


另一种启情况就是通过intent的标志位为Activity指定启动模式

Intent intent = new Intent();
intent.setClass(this,SecondActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

Activity 的 Flags

FLAG_ACTIVITY_NEW_TASK

这个标志位的作用是为Activity指向‘singleTask’启动模式,其效果和XML中指定该模式相同

FLAG_ACTIVITY_SINGLE_TOP

这个标志位的作用是为Activity指向‘singleTop’启动模式,其效果和XML中指定该模式相同

FLAG_ACTIVITY_CLEAR_TOP

具有此标记位的Activity,当他启动时,在同一个任务栈中所有位于他上面的Activity都要出栈,这个模式一般需要和FLAG_ ACTIVITY_ NEW _ TASK配合使用,在这种情况下,被启动的Activity的实例如果已经存在,那么系统就会调用它的onNewIntent,如果被启动的Activity采用标准模式,那么他连同他之上的Activity都要出栈,系统会创建新的Activity实例并放入栈顶

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

具有此标记位的Activity,不会出现在历史Activity的列表当中,当某种情况下我们不希望用户通过历史列表回到我们的Activity的时候就使用这个标记位了,他等同于在XML中指定Activity的属性: android:excludeFromRecents="true"

intentFilter的匹配规则

我们知道,启动Activity分为两种,显示调用和隐式调用,二者的区别这里就不多讲了,显示调用需要明确的指定被启动对象的组件信息,包括包名和类名,而隐式意图则不需要明确指定调用信息,原则上一个intent不应该即是显式调用又是隐式调用,如果二者共存的话以显式调用为主,显式调用很简单,这里主要介绍隐式调用,隐式调用需要intent能够匹配目标组件的IntentFilter中所设置的过滤信息,如果不匹配将无法启动目标Activity,IntentFilter中的过滤信息有action,category,data,下面是一个过滤规则的实例:

        
            
                
                
                
                
                
                
            
        

只有一个intent同时匹配action类别,category类别,data类别才算是匹配完成,只有完全匹配才能成功启动目标Activity。

1.action的匹配规则

action的匹配需求就是intent中的action存在且必和过滤规则一样的action,这里需要注意的是他和category匹配规则的不同,另外,action区分大小写,大小写不同的字符串匹配也会失败。

2.category的匹配规则

category的匹配规则和action不同,它要求Intent中如果含有category,那么所有的category都必须和过滤规则中的其中一个category相同。

Intent中可以没有category,原因是系统在调用startActivity或者startActivityForResult的时候会默认为Intent加上“android.intent.category.DEFAULT”这个category。

3.data匹配规则

data的匹配规则和action类似,它也要求Intent中必须含有data数据,并且data数据能够完全匹配过滤规则中的某一个data.这里的完全匹配是指过滤规则中出现的data部分也出现在了Intent中的data中。

参考资料:

《Android开发艺术探索》

Android开发艺术探索笔记

你可能感兴趣的:(Activity的生命周期和启动模式)