Activity生命周期与启动模式

Activity作为一个Android的基础知识,必须要熟悉的掌握它的各个阶段,才能去进行很好的开发。我希望在此篇自我学习的文章,不断反复重复强化Activity的基础知识。

概览

Activity的生命周期主要是分为几个阶段:

(1)onCreate():Activity正在创建,加载资源如界面布局,初始化等。

(2)onStart():Activity正在启动,到达后台,Activity可见,但不可与用户交互(用户看不到)

(3)onResume():Activity已经可见,在前台开始活动

(4)onPause():Activity正在**停止,紧接着onStop()就会被调用,此时快速回到Activity时,onResume会调用。位于后台 **

(5)onStop():Activity即将停止,在此时返回原Activity将通过onRestart()到达onStart()

(6)onDestroy():Activity即将被销毁,最后一站,重量级的回收工作和资源释放会在这里实现

(7)onRestart():Activity从onStop()重新返回onStart()

pkcd6Yt.png

onStop()和onStart()是随着用户操作或者设备屏幕的点亮和熄灭,所以被调用多次

onPause()存在的意义是和onResume()对比现在是否位于前台,并且如果调用新的Activity,onPause执行完毕以后才能调用新的Activity的onResume(),所以不能在onPause()中做重量级操作回收,这一点至关重要。

在几种情况下的启动

  1. 对于一个特定Activity A第一次启动:onCreate->onStart->onResume

打开新的Activity B或者切换到桌面:onPause->onStop(透明主题是不会调用onStop)

当 Activity 被另一个透明或者 Dialog 样式的 Activity 覆盖时的状态。此时它依然与窗口管理器保持连接,系统继续维护其内部状态,所以它仍然可见,但它已经失去了焦点故不可与用户交互,所以被覆盖的Activity并不会执行onStop()方法。

返回原来的Activity A的时候:onRestart->onStart->onResume

  1. 当按下back键:onPause()->onStop()->onDestroy()

启动的具体过程:首先启动Activity请求由Instrumentation来处理,通过Binder向AMS(ActivityManagerService)发送请求,在AMS内部的ActivityStack栈负责Activity状态同步,再通过ActivityThread去同步Activity状态完成生命周期方法的调用

启动过程源码分析:

1
2
3
4
5
6
7
boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, donWaitForPause);
if (mResumedActivity != null) {
// |=:两个二进制对应位都为0时,结果等于0,否则结果等于1;
pausing |= startPausingLocked(userLeaving, false, true, donWait-ForPause);
if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Pausing " + mResumeActivity);
}

我们都知道Activity的启动时根据栈来启动的,在启动新的Activity之前,栈顶的Activity先回调onPause()方法,新的Activity才会启动。

那么对于一个个应用来说,打开后在手机应用中后台算一个个的Task,而不算一个个Activity。切屏的时候其实就是在切换一个个的Task,每一个Task都有一个自己的回退栈,记录了用户打开的每一个Activity。当用户在调用返回键(back)的时候倒叙的来关闭每一个Activity,当回退栈的最后Activity被关闭了,那么就结束了这个Task,但是这个Task不会在最近任务列表里消失,系统会依然保留这个Task的残影给用户,用户点击了以后,其实不是会切回去,而是重新启动这个Activity。

那么如果在一个Task中的一个ActivityA打开了其他应用的ActivityB呢?例如:在短信APP ActivityA中点击复制号码点击添加联系人,就会打开通讯录APP中添加联系人ActivityB,此时这个ActivityB依然会放在这ActivityA的同一个Task中。当用户重新返回桌面打开通讯录的时候,不应该显示添加联系人这个ActivityB,而是应该是打开的联系人列表新的Activity。 注意:我们不应该以最近任务列表中的显示作为是否在同一个Task的依据,因为这是给用户看的,并不是给开发者看的

总结:Android一般默认规则是在不同的Task中打开同一个Activity,Activity会被创建多个实例,分别放进每一个Task。如果需要定制不同的逻辑,需要重写,如何重写就牵扯一些启动模式。

启动模式

  1. singleTask

singleTask可以让Activity被别的APP启动的时候,不会进入启动它的Task,而是会在属于它自己的Task去创建 。从名称来看,singleTask意思是一种单实例模式,多次启动Activity都不会重新创建新的实例,如果一开始没有实例就创建一个新的实例就可以。按下Back键,会显示用户上一个Activity,而不会直接返回到之前的APP

Task可以由前台进入后台:1. 按下Home返回桌面 2. 按最近任务键(方块键)查看最近任务

所以在这种模式下,系统不会调用Activity的onCreate()方法但是会调用onNewIntant()方法,限制了某个Activity在全局只存在一个对象。

总结::singleTask强调了唯一性,我只在一个Task里面,并且这个Task里面只有我一个实例

设置:android:launchMode=”singleTask”

1
2
3
4
5
6
7
8
9
10
11
12
<activity
android:name="com.someone.email.ComposeMileActivity"
android:launchMode="singleTask"
<inter-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.intent.action.SENDTO"/>
<action android:name="android.intent.action.SEND"/>
<data android:scheme="mailto"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
  1. singleInstance

与 “singleTask” 类似,只是系统不会将任何其他 Activity 启动到此Activity实例所在的任务栈中。该 Activity 始终是其任务栈唯一仅有的成员;由此 Activity 启动的任何 Activity 均在其他的任务栈中打开。

一旦该模式的Activity的实例存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例,其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中。

总结::singleInstance除了唯一性,还要求独占性。要独自霸占一个完整的Task。

  1. standard

默认。系统在启动这个 Activity 的任务中创建 此Activity 的新实例,并向其传送 Intent。

Activity 可以多次实例化,而每个实例均可属于不同的任务,并且一个任务可以拥有多个该activity实例。

  1. singleTop

单独使用时,只有当 当前任务栈的顶部已存在这个 Activity 的一个实例,则系统会通过调用该实例的 onNewIntent() 方法向其传送 Intent,而不是创建 Activity 的新实例。如果当前任务栈顶不是这个Activity则会创建新的实例。

例如,假设任务堆栈是 A-B-C-D;D 位于顶部。收到针对 D 类 Activity 的 Intent,

  • 如果 D 具有默认的 “standard” 启动模式,则会启动该类的新实例,且堆栈会变成 A-B-C-D-D。
  • 如果 D 的启动模式是 “singleTop”,则 D 的现有实例会通过 onNewIntent() 接收 Intent,因为它位于堆栈的顶部;而堆栈仍为 A-B-C-D。
  • 如果收到针对 B 类 Activity 的 Intent,则会向堆栈添加 B 的新实例,即便其启动模式为 “singleTop” 也是如此。

注:为某个 Activity 创建新实例时,用户可以按”返回”按钮返回到前一个 Activity。 但是当一个已经存在的Activity通过onNewIntent()在处理新的intent时,用户是不能通过返回键 回到这个Activity传入新intent之前的状态的。