Activity生命周期和启动模式

来源:互联网 发布:python基本数据类型 编辑:程序博客网 时间:2024/06/04 18:32

前言:最近整理了下2017这一年刷的书(为了加深记忆打算去做总结)

安卓方向:《Android群英传》丶《Android开发艺术探索》丶《Android系统源代码情景分析》

数据结构和算法:《大话数据结构》丶《数据结构与算法分析》丶《编程之美》丶《剑指offer》

设计模式:《Andorid源码设计模式》

其它:《Java并发编程实战》丶《图解HTTP》丶LintCode刷到中级(为了查答案又成了九章学员(>_<))

Activity的生命周期 

Activity生命周期分为两种:第一种是典型(正常)情况下的生命周期,第二种是异常情况下的生命周期。

~~~~第一种:典型情况下的生命周期:

(注:Activity生命周期切换过程)

针对图具体说明:

1:Avtivity第一次启动,回调:onCreate -> onStart ->OnResume。

2:当用户打开新的Activity或者切换到桌面时,回调:onPause ->onStop。特殊情况:如何新启动的Activity

      采用了透明主题时,回调onPause,不会回调onStop。

3:当用户再次回到原Activity,回调onRestart -> onStart ->onResume。

4:当用户按back键回退时,回调onPause ->onStop ->onDestroy。

5:当Activity被系统回收后再次打开,生命周期方法回调过程和1一样,注意只是生命周期方法一样,不代表所

      有过程都一样。

6:从整个生命周期方法来说,onCreate和onDestroy是配对的 ,对应Activity的创建与销毁;onStart                     和 onStop 是配对的,对应Activity的可见与不可见;onResume和onPause是配对的,对应可交互与不可           交互。(注:执行onStop方法后是不可见的,执行onPause方法后是不可交互的)

解答两个问题:

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

答:从实际使用过程来说,onStart和OnResume丶onPause和onStop看起来的确差不多,甚至我们可以只保

其中的一对。但这两个配对分别表示不同的意义,onStart和onStop是从Activity是否可见这个角度来回调的,

onResume和onPause是从Activity是否位于前台(即:可交互)角度来回调的。在实际使用中没有其他明显的区别。

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

答:Activity A 先执行onPause,然后新Activity B 的onCreate丶onStart丶onResume才被调用。(作者是从

Activity的启动过程中找的答案) >>>另:关于四大组件的启动过程《Android开发艺术探索》的第九章和《Android

系统源代码情景分析》的第七~九章都做了介绍,后面我也会去做下整理。

~~~~第二种异常情况下的生命周期:包含两种情况一种是:资源相关的系统配置发生改变;另一种是:系统内存

          不足时

*******一种:资源相关的系统配置发生改变(比如横竖屏切换)并不做特殊处理时:

(注:异常情况下Activity的重建过程)

说明:Activity会被销毁,其onPause丶onStop丶onDestroy均会被调用,同时会调用OnSaveInstanceState来
保存Activity的状态(视图结构),OnSaveInstanceState调用时机在onStop之前,与onPause无既定的时序关
系(即有可能在它之前也有可能在它之后)。当Activity被重新创建后,系统会回调onRestoreInstanceState, 并且会把OnSaveInstanceState方法保存的Bundle对象作为参数传递给onRestoreInstanceState和onCreate 。我们可以通过这两个方法来判断Activity是否被重建了,如果被重建了,我们就可以取出之前保存的数据并恢 复。。onRestoreInstanceState的调用时机在onStart之后。

解答三个问题:

1:OnSaveInstanceState和onRestoreInstanceState系统默认给我们做了哪些恢复工作 ?

答:当异常情况下需要重新创建时,系统会默认为我们保存当前Activity的视图结构,并且在Activity重启后为

我们恢复这些数据,比如文本框中用户输入的数据丶ListView滚动的位置等,这些View相关的状态系统都能够默认为我们恢复。如果我们想知道具体的某个View能为我们恢复哪些数据,我们可以查看View的源码。和Activity一样,每个View都实现了OnSaveInstanceState和OnSaveInstanceState这两个方法,看一下他们的具体实现就知道系统能够自动为每个View恢复哪些数据。

2:关于保存和恢复View层次结构,系统的工作流程是怎样的 ?

答:Activity被意外终止后,Activity会调用OnSaveInstanceState去保存数据,然后Activity会委托Window

去保存数据,接着Window在委托 它上面的顶级容器去保存数据。顶层容器是一个ViewGroup,一般来说是DecorView。然后顶层容器DecoreView再去一 一通知他的子元素来保存数据。这是一种典型的委托思想,上层委托下层丶父容器委托子元素去处理一件事。

3:当系统配置发生改变后Activity会被重新创建,那么有没有办法不重新创建呢 ?

答:有的。系统配置中有很多内容(比如:屏幕方向丶本地位置),如果当某项内容发生改变后,我们不想系统

重新创建Activity可以给Activity设置对应的configChanges属性。比如屏幕旋转的时候我们不想Acitivity重新创建就

可以给configChanges属性添加orientation这个值,多个值可以用"|"连接。

*******另一种:情况系统内存不足导致低优先级的Activity被杀死

先讲下Activity优先级的三种情况(从高到低):

1:前台Activity-----正在和用户交互的Activity,优先级最高。

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

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

当系统内存不足时,系统就会按照上述优先级去杀死目标Activity所在的进程,并后续通过

OnSaveInstanceState 和OnSaveInstanceState来存储和恢复数据。如果一个进程中没有四大组件在执行,那么这个

进程很容易被杀死,比较好 的方法就是将后台工作放入Service中从而保证此进程有一定的优先级,这样就不会被轻

易杀死。

Activity启动模式

Activity启动模式:为了满足项目的特殊需求Andorid设计者为我们提供了四种启动模式:standard丶

singleTop丶singleTask和singleInstance下面先一 一介绍其含义:

1:standard :标准启动模式,也是系统默认的模式。每次启动都会重新创建一个新的实例,不管这个实例是否

存 在。生命周期方法同与正常情况,onCreate->onStart->onResume都会被调用。这是一种典型的多实例实现,

一个任务栈中可以有多个相同实例,每个相同实例也可以属于不同的任务栈。

注意:在这种模式下谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。比如

activity A 启动了activity B ,那么B 就会进入到A所在的栈中。假如我们用ApplicationContext或Service去启动

standard模式的Activity就会报错,因为非Activity类型的Context并没有所谓的任务栈。可以通过为待启动的

Activity指定FLAG_ACTIVITY_NEW_TASK标记位这样就会为它创建一个新的任务栈。

 2:singleTop :栈顶复用模式。如果新Activity已经位于任务栈的栈顶,那么此Activity就不会被重新创建。同

时onNewIntent会被回调,新activity的onCreate丶onStart丶onResume不会被调用。如果新Activity已存在但不是

位于栈顶,那么新Activity仍然会被重新创建。比如:假设目前栈内情况为ABCD,其中ABCD是为四个Activity,A

位于栈底,D位于栈顶,再次启动D,如果D的启动模式为singleTop,那么栈内的情况仍然为ABCD。如果D的启动

模式为standard,那么D会被重新创建,导致栈内的情况变为ABCDD。

使用场景:适用于接收到消息后显示的界面,例如QQ接收到消息后弹出Activity,如果一次来10条消息,总不

能弹10个Activity。

3:singleTask:栈内复用模式。这是一种单实例模式,只要Activity在一个栈中存在,那么多次启动此Activity

都不会重新创建实例,并会回调onNewIntent 。具体一点,当一个具有singleTask模式的Activity请求启动后,比如

说Activity A,系统首先会寻找是否存在A 想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建A的实例后

把A放到栈中。 如若存在A所需的任务栈,这时要看A是否在栈中有实例存在,如果有实例存在,那么系统就会把A调

到栈顶,如果实例不存在,就创建A的实例并把A压入栈中。

举几个例子:1:比如目前任务栈S1中的情况为ABC,这个时候Activity D 以singleTask模式请求启动,其所需

要的任务栈为S2,由于S2和D的实例均不存在,所以系统会先创建任务栈S2,然后再创建D的实例并将其入栈到S2。

2:假设D所需要的任务栈为S1,其它情况如上面例子1所示,那么由于S1已经存在,所以系统会直接常见D的实

例并将其入栈到S1。3:如果D所需的任务栈为S1,并且当前任务栈S1的情况为ABCD根据栈内复用的原则,此时D

不会重新创建,系统 会把D切换到栈顶同时singleTask默认具有clearTop的效果,会导致栈内所有在D上面的

Activity全部出栈,于是最终S1中的情况为AD。

使用场景:通常可以用来退出整个应用。比如讲主Activity设置为singleTask模式,然后在要退出的Activity中转

到主Activity,从而将主Activity之上Activity都清除,然后重写onNewIntent方法,在方法中加上一句finish(),将最

后一个Activity结束掉。

4:singleInstance:单实例模式。这是一种加强的singleTask模式,它除了具有singleTask模式的所有特性

外,还加强了一点,那就是具有此种模式的Activity只能单独地位于一个任务栈中,比如Acitivity A是singleInstance

模式,当A启动后,系统会为它创建一个新的任务栈,然后A独自在这个新的任务栈中,由于栈内复用的特性,后续

的请求均不会创建新的Acitivity,除非这个独特的任务栈被系统销毁了。

使用场景:常用于需要与程序分离的界面,如在SetupWizard中调用紧急呼叫。解释:如果应用A的任务栈中创

建了MainActivity实例,且启动模式为singleInstance,此时如果应用B也要激活MainActivity,则不需要创建,两

个应用共享该Activity实例。

1:解释singleTask启动模式中,多次提到某个Activity所需的任务栈,什么是Activity所需的任务栈?

答:这要从一个参数说起:TaskAffinity,可以翻译为任务相关性。这个参数标识了一个Acitivity所需要的任务

栈的名字,默认情况下,所有Activity所需的任务栈的名字为应用的包名。当然,我们可以为每个Activity都单独制定

TaskAffinity属性,这个属性值必须不能和包名相同,否则就相当于没有指定。TaskAffinity主要和singleTask启动模

式或者allowTaskReparenting属性配对使用,在其它情况下没有意义。当TaskAffinity和singleTask启动模式配对使

用的时候,他是具有该模式的Activity的目前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任

务栈中。

2:如何给Activity指定启动模式呢?

答:第一种通过AndroidMenifest为Activity的launchMode属性设置相应的启动模式;第二种是通过

Intent.addFlags(标志位)为Activity指定启动模式。两种设置方式的区别:1:优先级上,第二种方式的优先级高于第

一种,当两者同时存在时以第二种。2:限定范围上有所不同,第一种方式无法直接为Activity设定

FLAG_ACTIVITY_CLEAR_TOP标识,而第二种方式无法为Activity指定singleInstance模式。

Activity的标志位

Activity的Flags有很多,这里主要分析一些比较常用的标记位。标记位的作用很多,有的标记位可以设置

Activity的启动模式,比如FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_SINGLE_TOP等;还有的标记位可以影响

Activity运行状态FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS等。在使用标记位的

时候,要注意有些标记位是系统内部使用的,应用程序不需要去手动设置这些标记位以防出现问题。下面介绍几种常

用的标记位:

1:FLAG_ACTIVITY_NEW_TASK

这个标记位的作用是为Activity指定“singleTask”启动模式,其效果和在XML中指定该启动模式相同

2:FLAG_ACTIVITY_SINGLE_TOP

这个标记位的作用是为Activity指定“singleTop”启动模式,其效果和在XML中指定该启动模式相同

3: FLAG_ACTIVITY_CLEAR_TOP

具有次标记位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈,这个标记位一

般和singleTask启动模式一起出现,在这种情况下,被启动activity如果已经存在,那么系统就会调用的它的

onNewIntent。如果被启动的Activity采用standar模式启动,那么它连同它之上的Activity都要出栈,系统会创建新

的Activity实例并放入栈顶。

4:FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

具有这个标记的Activity不会出现在历史Activity的列表中,当某些情况下我们不希望用户通过历史列表回到我

们的Activity的时候这个标记比较有用。它等同于在XML中指定Activity的属性android:excludeFromRecents =

 "true"。

^_^感谢您的阅读^_^

原创粉丝点击