第1章-Activity 的生命周期和启动模式读书笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/willway_wang/article/details/83040883

目录

1 Activity 的生命周期

1.1 Activity 的生命周期方法有哪些?

常用的生命周期方法有 7 个,如下:

  • onCreate:表示 Activity 正在被创建;
  • onRestart:表示 Activity 正在被重新启动;
  • onStart:表示 Activity 正在启动;
  • onResume:表示 Activity 已经可见了,并且出现在前台并开始活动;
  • onPause:表示 Activity 正在停止;
  • onStop:表示 Activity 即将停止;
  • onDestroy:表示 Activity 即将被销毁。

1.2 正常情况下,Activity 的生命周期切换过程是怎样的?

  • 针对一个特定的 Activity,第一次启动,回调为:onCreate -> onStart -> onResume;
  • 当用户打开新的 Activity 或者切换回桌面的时候,回调为:onPause -> onStop,而当新 Activity 采用了透明主题或者是 Dialog 主题 时,则当前 Activity 不会回调 onStop;
  • 当用户再次回到原 Activity 时,回调为:onRestart -> onStart -> onResume;
  • 当用户按 back 键回退时,回调为:onPause -> onStop -> onDestroy。

1.3 onStart 和 onResume、onPause 和 onStop 的区别是什么?

onStart 和 onStop 是从 Activity 是否可见这个角度来回调的,而 onResume 和 onPause 是从 Activity 是否位于前台这个角度来回调的。

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

从源码中可以得出结论,是旧 Activity 先 onPause,然后新 Activity 再 onResume。因此,不能在 onPause 中做重量级的操作,以免影响新 Activity 进入前台。

1.5 异常情况下,Activity 的生命周期过程是怎样的?

分为两种情况来说明:

  • 资源相关的系统配置发生改变导致 Activity 被杀死并重新创建:
    当系统配置发生变化(比如旋转屏幕)后, Activity 会被销毁,其 onPause、onStop、onDestroy 均会被调用,同时由于 Activity 是在异常情况下终止的, onSaveInstanceState 会被调用来保存当前 Activity 的状态。当 Activity 被重新创建后,系统会调用 onRestoreInstanceState 用来恢复之前保存的状态。
  • 资源内存不足导致低优先级的 Activity 被杀死:
    Activity 的优先级分为三种:前台 Activity,可见但非前台 Activity,后台 Activity。当系统内存不足时,系统会按照上述优先级去杀死目标 Activity 所在的进程,并在后续通过 onSaveInstanceState 和 onRestoreInstanceState 来保存和恢复数据。

1.6 onSaveInstanceState 什么情况下会被调用?

在 Activity 被异常终止时会被调用,在重建时回调 onRestoreInstanceState;
在按 Home 键或者启动新 Activity 时会单独调用 onSaveInstanceState。

1.7 onSaveInstanceState 和 onRestoreInstanceState 在生命周期中的调用时序是什么?

onSaveInstanceState 是在 onStop 之前,但和 onPause 没有既定的时序关系;
onRestoreInstanceState 是在 onStart 之后。

1.8 onCreate 和 onRestoreInstanceState 恢复数据时的区别是什么?

onRestoreInstanceState 一旦被调用,其参数 Bundle savedInstanceState 一定是有值的,不用进行判空操作;但是 onCreate 在正常启动时,其参数 Bundle savedInstanceState 为 null,需要进行判空操作。建议采用 onRestoreInstanceState 来恢复数据。

相关面试题

Q1:Activity 上有 Dialog 时按 Home 键时的生命周期

A:onPause -> onSaveInstanceState -> onStop。需要注意的是,在 Activity 中弹出 Dialog 时,并不会回调 onPause 方法;按 Home 键会单独触发 onSaveInstanceState 方法。

Q2:两个 Activity 跳转时必然会执行的是哪几个方法?

A:分情况分析一下:
当 Activity A 中打开新的 Activity B 时,这时 A 会回调 onPause、onSaveInstanceState、onStop,B 会回调 onCreate、onStart、onResume;
当 Activity A 中打开透明主题的 Activity B 时,这时 A 会回调 onPause、onSaveInstanceState,B 会回调 onCreate、onStart、onResume;
当 Activity A 打开 Activity B 时,B 已经存在于栈顶并且 B 的启动模式是 singleTop,这时 A 会回调 onPause、onSaveInstanceState、onStop,B 会回调 onNewIntent、onResume 方法。
综上分析,A 必然执行的方法是 onPause、onSaveInstanceState,B 是 onResume。

2 Activity 的启动模式

2.1 Activity 的四种启动模式对比?

  • standard (标准模式),这是系统的默认模式。每次启动一个 Activity都会创建一个新的实例,不管这个实例是否已经存在。被创建的实例的生命周期符合典型情况下的 Activity 的生命周期。
  • singleTop(栈顶复用模式)。在这种模式下,若新 Activity 已经位于任务栈的栈顶,那么此 Activity 不会被重新创建,同时它的 onNewIntent 方法会被回调,但是 onCreate、onStart 方法不会被系统调用(这是因为它并有发生改变)。若新 Activity 的实例已存在但不是位于栈顶,那么新 Activity 仍然会重新创建。
  • singleTask(栈内复用模式),这是一种单实例模式。在这种模式下,只要 Activity 在一个栈中存在,那么多次启动此 Activity 都不会重新创建实例,同时它的 onNewIntent 方法会被回调。
  • singleInstance(单实例模式),这是一种加强的 singleTask 模式。加强的是具有此种模式的 Activity 只能单独地位于一个任务栈中。

2.2 指定 Activity 启动模式的方法及其区别是什么?

启动模式允许你去定义如何将一个Activity的实例和当前的任务进行关联,有两种方法,第一种是在 AndroidManifest 中通过 android:launchMode 属性来给 Activity 指定启动模式,第二种是通过在 Intent 中设置标志位来为 Activity 指定启动模式。也就是说,当 Activity A 启动了 Activity B,第一种方式是 Activity B 定义自己如何与当前的任务进行关联,第二种方式是 Activity A 在 Intent 中要求 Activity B 怎样与当前任务进行关联。
区别:首先,优先级上,第二种方式的优先级要高于第一种,当两种都存在时,以第二种为准;其次,上述两种方式在限定范围上不同,比如,第一种方式无法直接为 Activity 设置 FLAG_ACTIVITY_CLEAR_TOP 标志,而第二种方式无法为 Activity 指定 singleInstance 模式。

2.3 查看任务栈的命令是什么?

adb shell dumpsys activity

2.4 有 3 个 Activity:A、B 和 C。其中 A 的启动模式是 standard,taskAffinity 是默认的,B 和 C 的启动模式是 singleTask,taskAffinity 不是默认的。进行如下操作,在 A 中单击按钮启动 B, 在 B 中单击按钮启动 C,在 C 中单击按钮启动 A,最后在 A 中单击按钮启动 B,现在按 2 次 back 键,然后看到的是哪个 Activity?

答案是回到桌面。

2.5 Activity 的 Flags

下面是几个常用的标记位:

  • FLAG_ACTIVITY_NEW_TASK
    设置了这个flag,新启动Activity就会被放置到一个新的任务当中(与"singleTask"有点类似,但不完全一样)。和 “singleTask” 的区别是:当使用 ApplicationContext 去启动一个 standard 的 Activity 时会报错,

    android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
    

    这时只能通过给 Intent 添加 FLAG_ACTIVITY_NEW_TASK 的方式解决报错,通过给新 Activity 添加 android:launchMode=“singleTask” 的方式是不能解决报错的。

  • FLAG_ACTIVITY_SINGLE_TOP
    等同于为 Activity 指定 “singleTop” 启动模式。

  • FLAG_ACTIVITY_CLEAR_TOP
    设置了这个flag,如果要启动的Activity在当前任务中已经存在了,就不会再次创建这个Activity的实例,而是会把这个Activity之上的所有Activity全部关闭掉。。比如说,一个任务当中有A、B、C、D四个Activity,然后D调用了startActivity()方法来启动B,并将flag指定成FLAG_ACTIVITY_CLEAR_TOP,那么此时C和D就会被关闭掉,现在返回栈中就只剩下A和B了。

    那么此时Activity B会接收到这个启动它的Intent,你可以决定是让Activity B调用onNewIntent()方法(不会创建新的实例),还是将Activity B销毁掉并重新创建实例。如果Activity B没有在manifest中指定任何启动模式(也就是"standard"模式),并且Intent中也没有加入一个FLAG_ACTIVITY_SINGLE_TOP flag,那么此时Activity B就会销毁掉,然后重新创建实例。而如果Activity B在manifest中指定了singleTop 或者 singleTask,或者是在Intent中加入了一个FLAG_ACTIVITY_SINGLE_TOP flag,那么就会调用Activity B的onNewIntent()方法。

2.6 当调用startActivity()方法来启动一个Activity时,如果在Intent中加入了一个FLAG_ACTIVITY_NEW_TASK flag的话(或者该Activity在manifest文件中声明的启动模式是"singleTask"),一定会开始一个新的任务栈吗?

系统就会尝试为这个Activity单独创建一个任务。但是规则并不是只有这么简单,系统会去检测要启动的这个Activity的affinity和当前任务的affinity是否相同,如果相同的话就会把它放入到现有任务当中,如果不同则会去创建一个新的任务。而同一个程序中所有Activity的affinity默认都是相同的,这也是前面为什么说,同一个应用程序中即使声明成"singleTask",也不会为这个Activity再去创建一个新的任务了。

3 IntentFilter 的匹配规则

3.1 启动 Activity 的两种方式

显式调用和隐式调用。显式调用优先于隐式调用。显式调用需要明确地指定被启动对象的组件信息,包括包名和类名;隐式调用不需要明确指定组件信息,需要 Intent 能够匹配目标组件的 IntentFilter 中所设置的过滤信息。

3.2 action 的匹配规则

action 的匹配要求 Intent 中的 action 存在且必须和过滤规则中的其中一个 action 相同。注意,Intent 中如果没有指定 action,那么匹配失败。

3.3 category 的匹配规则

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

3.4 data 的匹配规则

data 要求 Intent 中必须含有 data 数据,并且 data 数据能够完全匹配过滤规则中的某一个 data。data 有两部分组成,mimeType 和 URI。

3.5 为什么隐式调用时,必须在 intent-filter 中指定 “android.intent.category.DEFAULT” 这个 catogery?

这是因为系统在调用 startActivity 或者 startActivityForResult 的时候会默认为 intent加上 “android.intent.category.DEFAULT” 这个 catogery。如果不指定,就会匹配失败。

参考

1.《Android开发艺术探索》
2. Android任务和返回栈完全解析,细数那些你所不知道的细节

猜你喜欢

转载自blog.csdn.net/willway_wang/article/details/83040883
今日推荐