天天看点

第一章 Activity的生命周期和启动模式

1.1 Activity的生命周期全面分析

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

异常情况下的生命周期:指Activity被系统回收或者由于当前设备的configuration(配置)发生改变导致Activity被销毁重建,异常情况下的生命周期和典型情况下的生命周期略有不同。

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

Activity完整的生命周期:

onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy
           

onStart ():表示 Activity 已经是可见状态,但是还没有出现在前台,无法和用户进行交互。但是可以理解为 Activity 已经显示出来了,只是我们还看不到。DecorView 还没有被 WindowMannager 添加。

onResume():此时的 Activity 也是可见状态,出现在前台并且可以可用户交互,而 start() 的时候 Activity 还是在后台。

onPause():表示 Activity 正在停止,此时可以做一些存储数据、停止动画等操作,但是不能耗时,因为有新的Activity展示在前台的时候,onPause() 必须先执行完,新 Activity 的 onResume() 才能执行。切换到新的 Activity 的时候,onPause -> onStop;但是如果新的 Activity 是透明主题,那么当前 Activity 不会执行 onStop。

onStop():表示 Activity 即将停止,可以做一些稍微重量级别的回收工作,但是同样不能太耗时。

onDestroy(): 表示 Activity 即将被销毁,可以做一些回收和最终的资源释放。

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

实际使用上其实是差不多的,但是两个配对的回调代表着不同的意义。onStart 和 onStop 是从 Activity 是否可见这个角度来回调的,onResume 和 onPause 是从 Activity 是否位于前台这个角度来回调的,除了这个区别,在实际使用中没有其它明显区别。

问题2:假设当前 Activity 为 A,如果这时用户打开一个新 Activity B,那么 B 的 onResume 和 A 的 onpause 哪个先执行呢?

官方文档:不能在 onPause 中做重量级操作,因为必须 onPause 执行完成以后新 Activity 才能 Resume。

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

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

当系统配置(比如旋转屏幕)发生改变,Activity 会被销毁。由于 Activity 是在异常情况下终止的,系统调用 onSaveInstanceState(),该方法在 onStop 之前调用。当 Activity 被重新创建后,系统会调用 onRestoreInstanceState(),并且把 Activity 销毁时 onSaveInstanceState() 方法所保存的 Bundle 对象作为参数同时传递给 onRestoreInstanceState() 和 onCreate(), onRestoreInstanceState() 在onStart() 方法执行时候执行。

保存和恢复 View 层次结构,系统的工作流程:首先 Activity 被意外终止了,Activity 会调用 onSaveInstanceState() 去保存数据,然后委托 Window 保存数据,接着 Window 委托它上面的顶层容器保存数据,一般是指 DecorView ,最后顶层容器会一一通知子元素保存数据,每个子元素也有 onSaveInstanceState() 和 onRestoreInstanceState() 。这种典型的委托思想,类似:View的绘制过程、事件分发。

onRestoreInstanceState() 和 onCreate() 区别:

onRestoreInstanceState() 一旦被调用,一定是有值的,不用额外判断是否为空,但是 onCreate() 如果是正常启动的话,参数 Bundle savedInstanceState 为空,所以必须要进行判断。

系统只在 Activity 异常终止的时候才会调用 onSaveInstanceState() 和 onRestoreInstanceState() 来保存和恢复数据,其它情况下会触发这个过程。但是按 Home 键或者启动新 Activity 仍然会单独触发 onSaveInstanceState()的调用,但是再次回到该 Activity 的时候不会调用 onRestoreInstanceState(),调用 onStart() 。

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

Activity 按照优先级从高到低:

(1):前台 Activity —— 正在和用户交互的 Activity,优先级最高

(2):可见但非前台 Activity —— 比如 Activity 中弹出了一个对话框,导致 Activity 可见但是位于后台无法和用户直接交互。

(3):后台 Activity —— 已经被暂停的 Activity,比如执行了 onStop,优先级最低。

当系统内存不足时,系统就会按照上述优先级杀死目标 Activity 所在的进程,并在后续通过 onSaveInstanceState() 和 onRestoreInstanceState() 来存储和恢复数据。如果一个进程中没有四大进程在执行,那么这个进程将很容易被系统杀死。因此,一些后台工作不适合脱离四大组件而独立运行在后台中,这样进程很容易被杀死。比较好的方法是将后台工作放入 Service 中保证进程有一定的优先级,这样就不会轻易地被系统杀死。

当系统配置发生改变后,Activity 会被重新创建,可以给 Activity 指定 configChanges 属性。

1.2 Activity 的启动模式

1. Activity 的 LaunchMode

(1) standard:标准模式

系统的默认模式,当用 ApplicationContext 去启动 standard 模式的 Activity会报错,因为 standard 模式的 Activity 默认会进入启动它的 Activity 所在的栈,但是非 Activity 类型的 Context 并没有所谓的任务栈。解决此问题的方法是为待启动的 Activity 指定 FLAG_ACTIVITY_NEW_TASK 标记位(在 intent 中设置),这样启动的时候就会为它创建一个新的任务栈。此时待启动 Activity 实际以 singleTask 模式启动的。

(2) singleTop:栈顶复用模式

如果新 Activity 已经在栈顶,则此 Activity 不会被创建,不会走 Activity 的onCreate() 和 onStart() 方法, onNewIntent() 方法被调用;如果新 Activity 的实例已经存在但是不在栈顶,那么新 Activity 仍然会被重建。

(3) singleTask:栈内复用模式

这是一种单实例模式,当一个具有 singleTask 模式的 Activity 请求启动后,比如 Activity A,系统首先会寻找是否存在 A 想要的栈,如果不存在,就创建一个任务栈,然后创建 A 的实例后把 A 放到栈中。如果存在 A 所需的任务栈,这时要看栈中是否有实存在,如果有实例存在,那么系统就会把该实例之上的 Activity 实例出栈,并调用 Activity 的 onNewIntent,如果实例不存在,就创建 A 的实例并把 A 放入栈中。

(4) singleInstance:单实例模式

具有 singleTask 的所有特性,这种模式的 Activity 只能单独地位于一个任务栈中。

2. TaskAffinity 和 allowTaskReparenting

TaskAffinity 标识了一个 Activity 所需要的任务栈的名字,默认情况,所有 Activity 的任务栈名字为应用的包名,单独指定该参数值的时候,不能与包名相同。该属性主要和 singleTask 和 allowTaskReparenting 配对使用,其他情况下没有意义。

TaskAffinity 和 singleTask 配对使用的时候,待启动的 Activity 会运行在名字和 TaskAffinity 值相同的任务栈中。

TaskAffinity 和 allowTaskReparenting 配对使用的时候,当一个应用 A 启动应用 B 的某个 allowTaskReparenting 属性为 true 的 Activity,那么当应用 B 再启动的时候,在 A 中启动的 B 的 Activity 会从应用 A 的任务栈转移到应用 B 的任务栈中。

给 Activity 指定启动模式有两种,第一种是在 AndroidManifest.xml 中指定,另一种通过在 Intent 实例中设置标记位。 区别:1. 限定范围有所不同。2. 第二种的优先级较第一种更高。

3. Activity 的 Flags

常用标记位:

Intent.FLAG_ACTIVITY_NEW_TASK:和给 Activity 指定 singleTask 启动模式效果一样。

Intent.FLAG_ACTIVITY_SINGLE_TOP:和 singleTop 效果相同。

Intent.FLAG_ACTIVITY_CLEAR_TOP: 具有此标记位的 Activity,当它启动时,在同一个任务栈中所有位于它上面的 Activity 都要出栈。通常和 singleTask 一块出现,这种情况下,被启动的 Activity 实例如果已经存在,系统会调用它的 onNewIntent。如果被启动的 Activity 采用 standard 模式启动,那么它连同它之上的 Activity 都要出栈,系统会创建新的 Activity 实例并放入栈中。

Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS: 具有该标记的 Activity 不会出现在历史 Activity 列表中,某些情况下,我们不想用户通过历史列表回到我们的 Activity 的时候这个标记比较有用。等同于在配置文件中指定 Activity 的属性

android:excludeFromRecents="true"

1.3 IntentFilter 的匹配规则

IntentFilter 的过滤信息有 action、category、data。只有一个 Intent 同时匹配 action类别、category 类别、data 类别才算完全匹配,只有完全匹配才能成功启动 Activity。一个 Activity 可以有多个 intent-filter,一个 Activity 只要能匹配其中一组就可以成功启动对应的 Activity。

1. action 的匹配规则

匹配必须字符串完全相同,并区分大小写。一个过滤规则中可以有多个 action,Intent 中的 action 必须存在且能和过滤规则中的任何一个 action 匹配成功即可。

2. category 的匹配规则

category 要求 Intent 可以没有 category,但是如果一旦有 category,不管有几个,每隔都要能和规律规则中的任何一个 category 相同。

3. date 的匹配规则

匹配规则类似于 action,要求 Intent 中必须要有 data 数据,并且 data 数据能够完全匹配过滤规则中的某一个 data。

语法如下:

<data 
                    android:scheme="string"
                    android:host="string"
                    android:port="string"
                    android:path="string"
                    android:pathPattern="string"
                    android:pathPrefix="string"
                    android:mimeType="string"/>
           

继续阅读