1_Activity生命周期分析

声明:

这仅仅是对Android开发大神 任玉刚的作品《Android开发艺术探索》内容的誊写,不存在以广告、盈利等其他任何商业行为,仅仅是因书籍携带不便,不能随时“瞻仰”大神作品,故将书中内容誊写下来,(注:内容全部手打)。



正常情况下Activity生命周期如图image

有7个生命周期回调 当用户打开新的Activity或者桌面的时候, 正常是onPause->onStop. 有一种特殊情况下,如果新Activity采用了透明主题,那么当前Activity不会回调onStop.

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

从实际使用过程来说看起来的确差不多,甚至我们 可以只保留其中一对,那为什么Android系统还要提供看起来重复的接口呢?这两个配对的回调分别表示不同的意义,onStart和onStop是从Activity是否可见这个角度来回调的,而onResume和onPause是从Activity是否位于前台这个角度来回调的,除了这种区别,在实际使用中没有其他明显区别。

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

当启动一个Activity的时候,旧的Activity的onPause会先执行,然后才会启动新的Activity。也就是A的onPause先执行完成后,B的onCreate,onStart,onResume然后A的onStop这样的顺序,Android官方文档对onPause的解释有这么一句:不能再onPause中做重量级的操作,因为必须onPause执行完成以后新的Activity才能onResume。

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

Activity除了用户操作所导致的正常的生命周期的方法调度,还有一些异常情况,比如当资源相关的系统配置发生改变以及系统内存不足时,Activity就可能被杀死。

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

        为了兼容不同的设备,我们可能需要在其他一些目录放置不同的图片,这样当应用程序启动时,系统就会根

据当前设备的情况去加载合适的Resource资源,比如说横屏手机和竖屏手机拿到两张不同的图片。当前Activity横

竖屏切换,由于系统配置发生了改变,在默认情况下,Activity就会被销毁并且重新创建(当然我们也可以阻止系统

重新创建Activity)。 其onPause、onStop、onDestroy均会被调用,同时由于Activity是在异常情况下终止的,系

统会调用onSaveInstanceState来保存当前Activity的状态。这个方法的调用时机是在onStop之前,它和onPause

没有既定的时序关系,它既可能在onPause之前或之后调用。需要强调的一点事,这个方法只会在Activity被异常

终止的情况下,正常情况下系统不会回调这个方法。当Activity被重新创建后,系统会调用

onRestoreInstanceState,并且把Activity销毁时onSaveInstanceState方法所保存的Bundle对象作为参数同时传

递给onRestoreInstanceSate和onCreate方法。因此,我们可以通过onRestroreInstanceState和onCreate方法

来判断Activity是否被重建了,如果被重建了,那么我们就可以取出之前保存的数据并恢复,从时序上来说,

OnRestoreInstanceState的调用时机在onStart之后。 在onSaveInstacneState和onRestoreInstanceState方法

中系统自动为我们做了一定的恢复工作,比如系统会默认为我们保存当前Activity的视图结构,并且在Activity重启

后为我们恢复这些数据,比如文本框中用户输入的数据、滚动视图的位置等等。 和Activity一样,每个View都有

onSaveInstanceState和onRestoreInstanceState方法。 关于保存和恢复View层级结构,系统的工作流程是这样

的:首先Activity被意外终止时,Activity会调用onSaveInstanceState方法去保存数据,然后Activity会委托

window去保存数据,接着window再委托他上面的顶级容器去保存数据。顶级容器是一个ViewGroup,一般来说

它可能是DecorView。最后顶层容器再去一一通知他的子元素去保存数据,这样整个数据保存过程就完成了。这是

一典型的委托思想,上层委托下层、父容器委托子元素去处理一件事件,这种思想在Android中有很多应用,比如

View的绘制过程、事件分发等。 系统只在Activity异常终止时才会调用onSavaInstanceState与

onRestoreInstancestate来存储和恢复数据,其他情况下不会触发这个过程。但是按home键或者启动新的

Activity仍然会单独触发onSaveInstanceState的调用。

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

其数据存储和恢复过程和情况1完全一致。Activity优先级分为三种:

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

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

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

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

和onRestoreInstanceState来存储和恢复数据。如果一个进程没有四大组件在执行,那么这个进程将很快被系统

杀死,因此,一些后台工作不适合脱离四大组件而独立运行在后台中,这样的进程很容易被杀死。比较好的方法是

将后台工作放入Server从而保证进程有一定的优先级,这样就不会轻易被系统杀死。

Activity的启动模式 分别为stanard、singleTop、singleTask和singleInstance

系统的默认的启动模式,当我们多次启动同一个Activity时,系统会创建多个实例并把他们放到同一个任务栈中,任务栈是一种 “后进先出”,每按back键时,就会有一个Activity出栈,直到栈空为止,此时系统就会回收这个任务栈

(1)standard:标准模式,系统默认模式,每次启动一个Activity都会重新创建一个新的实例放到任务栈中,不

管这个实例是否存在。一个任务栈可以有多个实例,每个实例也可以属于不同的任务栈。在该模式下,谁启动了这

个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。当用applicationContext去启动

standard模式的Activity就会报错。因为standard模式下的Activity会默认进入启动它的Activity所在的任务栈中,

但非Activity类型的Context(如ApplicationContext)并没有所谓的任务栈,所以就有问题。解决这个问题就是

为待启动的Activity指定 FLAG_ACTIVITY_NEW_TASK标记位,这样启动的时候就会为他创建一个新的任务栈,这

个时候待启动的Activity实际上是以standard模式启动的。 (2)singleTop:栈顶复用模式。如果新的Activity已

经在栈顶了,那么这个Activity就不会被重新创建,同时它的onNewINtent方法就会被回调,如果新的Activity不

存在或存在但不位于栈顶,那么新的Activity就会被重新创建。

(3)singleTask:栈内复用模式。只要Activity在一个栈中存在,多次启动此Activity都不会被重新创建,会回调onNewIntent方法,同时将该Activity调到栈顶并将该Activity上面的Activity全部出栈。

(4)singleInstance:单实例模式.具有此种模式的Activity只能位于一个单独的任务栈中。每次重新创建也是栈内复用。

什么是Activity所需的任务栈?这要从一个参数说起,TaskAffinity可以理解为任务相关性,这个参数标识了一个

Activity所需的任务栈的名字,默认情况下,所有Activity所需的任务栈的名字都是应用的包名。TaskAfffinity属性

主要和SingleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有任何意义

(1)当TaskAffinity和allowTaskReparenting结合的时候,当一个应用A启动了应用B的一个Activity后,如果这

个Activity的allowTaskReparenting属性为true的话,同时按home键回到桌面,然后又启动应用B,此Activity会

直接从应用A的任务栈转移到应用B的任务栈中。

(2)当TaskAffinity和singleTask启动模式配对使用的时候,它是具有该模式的Activity所需任务栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中。

有两种方法指定Activity启动模式,第一种是通过AndroidMenifest中launchMode为Activity指定启动模式,第二

种是通过Intent中addFlags设置标志位。 在优先级上,第二种优先级高,当两种同时存在时以第二种为准;第一

种方式无法直接为Activity设定FLAG_ACTIVITY_CLEAR_TOP标识(销毁目标Activity和目标之上的Activity然后重

新创建目标Activity) 第二种方式无法为Activity指定singleInstance模式。

Activity的Flags

1 FLAG_ACTIVITY_NEW_TASK

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

2 FLAG_ACTIVITY_SINGLE_TOP

这个标记位为Activity指定SingleTop启动模式,效果和在xml指定该模式相同。

3 FLAG_ACTIVITY_CLEAR_TOP 这个标记位的Activity,当它启动时,在同一个任务栈中的所有位于它上面的

Activity都要出栈,这个模式下一般会和FLAG_ACTIVITY_NEW_TASK一起出现,被启动的Activity实例如果存在,

不会重新创建,会回调onNewIntent方法。如果被启动的Activity是standard模式,那么目标Activity和它上面的

Activity都要出栈,然后在创建目标Activity放入栈顶。

4 FLAG_ACTIVITY_EXCLUDE_FORM_RECENTS

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

的时候这个标记比较好用。等同于XML中指定Activity属性android:excludeFromRecents="true"。

IntentFilter匹配规则

当我们使用隐式方式启动一个Activity的时候,可以做一下判断,判断是否有Activity匹配我们的隐式Intent,如果不做判断的话,可能会出现找不到Activity的错误。

判断方法有两种:PackageManager的resolveActivity方法或queryIntentresolveActivity方法。前者返回最佳匹

配Activity的信息,后者返回所有能够成功匹配的Activity信息。具有共同的参数(Intenti intent,int flags) ,第

二个参数是要用MATCH_DEFAULT_ONLY这个标记位,这个标记位的含义是仅仅能匹配那些在intent_filter中声明

了<category android:name="android.intent.category.DEFAULT"/>的Activity。这个的意义是上述两个方法不

返回null时,startActivity一定会成功。如果不用这个标记位,就可以把过滤规则中category不含DEFAULT这个

category的Activity匹配出来,从而导致startActivity失败,因为过滤规则中category不含DEFAULT的Activity无

法接受隐式的Activity。

在action和category中,有一类action和category比较重要,它们是:

<action android:name="android.intent.action.MAIN"/>

<category android:name="android.intent.category.LAUNCHER"/>

这二者的作用是用来标明这是一个入口Activity,并且会出现在系统的应用列表中,缺少之一都没有实际意义,也无法出现在系统的应用列表中。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值