您的位置:首页 > 其它

Activity解析

2017-08-07 15:30 148 查看
本文主要讲述Activity的四个相关概念

Activity基础知识
activity生命周期图

onWindowFocusChangedonSaveInstanceStateonRestoreInstanceState调用时机

四种LauncheMode分析
Activity一共有以下四种launchMode

下面结合图例来解释

实例图如下

Activity Task分析
Activity Task相关的知识

affinity

Intent几种常见的flags

常用场景分析

本文主要讲述Activity的四个相关概念

Activity基础知识

LaunchMode

Task

常用场景分析

Activity基础知识

activity生命周期

onWindowFocusChanged、onSaveInstanceState、onRestoreInstanceState调用时机

activity生命周期图:

不再细说它的启动流程,说几个特殊的场景下,activity的状态变化:

- 当前Activity被其他Activity覆盖其上或被锁屏:系统会调用onPause方法,暂停当前Activity的执行。

- 当前Activity由被覆盖状态回到前台或解锁屏:系统会调用onResume方法,再次进入运行状态。

- 当前Activity转到新的Activity界面或按Home键回到主屏,自身退居后台:系统会先调用onPause方法,然后调用onStop方法,进入停滞状态。

- 用户后退回到此Activity:系统会先调用onRestart方法,然后调用onStart方法,最后调用onResume方法,再次进入运行状态。

- 当前Activity处于被覆盖状态或者后台不可见状态,即第2步和第4步,系统内存不足,杀死当前Activity,而后用户退回当前Activity:再次调用onCreate方法、onStart方法、onResume方法,进入运行状态。

- 用户退出当前Activity:系统先调用onPause方法,然后调用onStop方法,最后调用onDestory方法,结束当前Activity。



onWindowFocusChanged、onSaveInstanceState、onRestoreInstanceState调用时机:

onWindowFocusChanged

当Activity被创建时是在onResume之后被调用,当Activity被覆盖或者退居后台或者当前Activity退出时,它是在onPause之后被调用;

onSaveInstanceState

(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,此方法会被调用;

(2)在用户改变屏幕方向时,此方法会被调用;

(3)在当前Activity跳转到其他Activity或者按Home键回到主屏,自身退居后台时,此方法会被调用。

onSaveInstanceState的调用顺序是在onPause之前。

onRestoreInstanceState

(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,然后用户又回到了此Activity,此方法会被调用;(2)在用户改变屏幕方向时,重建的过程中,此方法会被调用。我们可以重写此方法,以便可以恢复一些临时数据。

onRestoreInstanceState的调用顺序是在onStart之后。

参考博客 —— [ 基础总结篇之一:Activity生命周期 ]

四种LauncheMode分析

Activity一共有以下四种launchMode:

standard

singleTop

singleTask

singleInstance

下面结合图例来解释:

1.standard

不管有没有已存在的实例,都生成新的实例。



如果以这种方式启动的Activity被跨进程调用,在5.0之前新启动的Activity实例会放入发送Intent的Task的栈的顶部,尽管它们属于不同的程序,这似乎有点费解看起来也不是那么合理,所以在5.0之后,上述情景会创建一个新的Task,新启动的Activity就会放入刚创建的Task中,这样就合理的多了。



2.singleTop

栈顶复用模式,如果要开启的activity在任务栈的顶部已经存在,就不会创建新的实例,而是调用 onNewIntent() 方法。避免栈顶的activity被重复的创建。



3.singleTask

栈内复用模式,activity只会在任务栈里面存在一个实例。如果要激活的activity,在任务栈里面已经存在,就不会创建新的activity,而是复用这个已经存在的activity,调用 onNewIntent() 方法,并且清空这个activity任务栈上面所有的activity

4.singleInstance

单一实例模式,整个手机操作系统里面只有一个实例存在。不同的应用去打开这个activity 共享公用的同一个activity。他会运行在自己单独,独立的任务栈里面,并且任务栈里面只有他一个实例存在。

实例图如下:







最近的一个需求:

后台有推送来了,弹出一个弹窗(实为透明底activity),在有一个弹窗实例后,如果继续推送,就会覆盖生成多个activity,这里就考虑使用了SingleTop,当然SingleTask也是OK的;使用时,要注意如何不生成新activity实例,而更新activity界面了。也就是在onNewIntent方法里该做哪些工作(onNewIntent()里要先调用setIntent()才使新intent生效):

具体可以参考:http://blog.csdn.net/findsafety/article/details/9664061

参考博客1 —— [ 基础总结篇之二:Activity的四种launchMode ]

参考博客2 —— [ 我打赌你一定没搞明白的Activity启动模式 ]

Activity Task分析

task是一个具有栈结构的容器,可以放置多个Activity实例。启动一个应用,系统就会为之创建一个task,来放置根Activity;默认情况下,一个Activity启动另一个Activity时,两个Activity是放置在同一个task中的,后者被压入前者所在的task栈,当用户按下后退键,后者从task被弹出,前者又显示在幕前,特别是启动其他应用中的Activity时,两个Activity对用户来说就好像是属于同一个应用;系统task和task之间是互相独立的,当我们运行一个应用时,按下Home键回到主屏,启动另一个应用,这个过程中,之前的task被转移到后台,新的task被转移到前台,其根Activity也会显示到幕前,过了一会之后,在此按下Home键回到主屏,再选择之前的应用,之前的task会被转移到前台,系统仍然保留着task内的所有Activity实例,而那个新的task会被转移到后台,如果这时用户再做后退等动作,就是针对该task内部进行操作了。

Activity Task相关的知识:

Activity的affinity(亲和力)

Intent几种常见的flags

activity与task相关属性

affinity

affinity对于Activity来说就好像它的身份证一样,可以告诉所在的task,自己属于这个task中的一员;拥有相同affinity的多个Activity理论同属于一个task,task自身的affinity决定于根Activity的affinity值。

affinity在什么场合应用呢?

1.根据affinity重新为Activity选择宿主task(与allowTaskReparenting属性配合工作);

2.启动一个Activity过程中Intent使用了FLAG_ACTIVITY_NEW_TASK标记,根据affinity查找或创建一个新的具有对应affinity的task。我们会在后面进行详细讲解。

默认情况下,一个应用内的所有Activity都具有相同的affinity,都是从Application(参考application的taskAffinity属性)继承而来,而Application默认的affinity是 manifest 中的包名我们可以为application设置taskAffinity属性值,这样可以应用到application下的所有activity,也可以单独为某个Activity设置taskAffinity。例如:在系统自带的Browser中,package为com.Android.browser,但是application却自定义一个taskAffinity属性值:

<application   android:name="Browser"
android:label="@string/application_name"
android:icon="@drawable/ic_launcher_browser"
android:backupAgent=".BrowserBackupAgent"
android:taskAffinity="android.task.browser" >


Intent几种常见的flags:

1.FLAG_ACTIVITY_NEW_TASK:

当Intent对象包含这个标记时,系统会寻找或创建一个新的task来放置目标Activity,寻找时依据目标Activity的taskAffinity属性进行匹配,如果找到一个task的taskAffinity与之相同,就将目标Activity压入此task中,如果查找无果,则创建一个新的task,并将该task的taskAffinity设置为目标Activity的taskActivity,将目标Activity放置于此task。注意,如果同一个应用中Activity的taskAffinity都使用默认值或都设置相同值时,应用内的Activity之间的跳转使用这个标记是没有意义的,因为当前应用task就是目标Activity最好的宿主。

举个例子说明:

1.新建两个项目,分别命名为appA和appB,并且分别创建FirstActivity和SecondActivity,我们准备让appB中的FirstActivity跳转到appA的SecondActivity。

我们要演示几个步骤:1.在appB中的FirstActivity点击按钮跳转到appA中的SecondActivity;2.按Home键回到主屏,在主选单中再次启动appB;3.按Home键回到主屏,在主选单中启动appA。

不加FLAG_ACTIVITY_NEW_TASK时:

appB跳转到appA的SecondActivity之后,SecondActivity实例好像是嵌入到了appB中,但是不影响appA的正常运行,这种关系如下图所示:



加上FLAG_NEW_TASK标记:

我们再次启动appB时已经看不到刚才启动的appA中的SecondActivity,而启动appA时却直接看到了,说明这个SecondActivity实例并不在appB的task内,而是创建了一个task,这个task的affinity就是SecondActivity默认的affinity,由于appA的SecondActivity的affinity是从Application继承而来,所以当appA启动时会直接找到这个task,而不是创建新的task



另一个实验可以见图示:



2.FLAG_ACTIVITY_CLEAR_TOP:

当Intent对象包含这个标记时,如果在栈中发现存在Activity实例,则清空这个实例之上的Activity,使其处于栈顶。例如:我们的FirstActivity跳转到SecondActivity,SecondActivity跳转到ThirdActivity,而ThirdActivity又跳到SecondActivity,那么ThirdActivity实例将被弹出栈,使SecondActivity处于栈顶,显示到幕前,栈内只剩下FirstActivity和SecondActivity。这个SecondActivity既可以在onNewIntent()中接收到传来的Intent,也可以把自己销毁之后重新启动来接受这个Intent。在使用默认的“standard”启动模式下,如果没有在Intent使用到FLAG_ACTIVITY_SINGLE_TOP标记,那么它将关闭后重建,如果使用了这个FLAG_ACTIVITY_SINGLE_TOP标记,则会使用已存在的实例;对于其他启动模式,无需再使用FLAG_ACTIVITY_SINGLE_TOP,它都将使用已存在的实例,Intent会被传递到这个实例的onNewIntent()中

3.FLAG_ACTIVITY_SINGLE_TOP:

当task中存在目标Activity实例并且位于栈的顶端时,不再创建一个新的,直接利用这个实例。我们在上边的例子中也有讲到。

4.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET:

如果一个Intent中包含此属性,则它转向的那个Activity以及在那个Activity其上的所有Activity都会在task重置时被清除出task。当我们将一个后台的task重新回到前台时,系统会在特定情况下为这个动作附带一个FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记,意味着必要时重置task,这时FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET就会生效。经过测试发现,对于一个处于后台的应用,如果在主选单点击应用,这个动作中含有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记,长按Home键,然后点击最近记录,这个动作不含FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记,所以前者会清除,后者不会。关于这个标记,可以下图示之:

这个标记对于应用存在分割点的情况会非常有用。比如我们在应用主界面要选择一个图片,然后我们启动了图片浏览界面,但是把这个应用从后台恢复到前台时,为了避免让用户感到困惑,我们希望用户仍然看到主界面,而不是图片浏览界面,这个时候我们就要在转到图片浏览界面时的Intent中加入此标记。

常用场景分析

1.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息