当前位置: 移动技术网 > IT编程>移动开发>Android > Android基础总结篇之三:Activity的task相关介绍

Android基础总结篇之三:Activity的task相关介绍

2019年07月24日  | 移动技术网IT编程  | 我要评论

本篇文章主要介绍了android基础总结篇之三:activity的task相关,具有一定的参考价值,有需要的可以了解一下。

今天我们来讲一下activity的task相关内容。

上次我们讲到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内部进行操作了。

我们今天就讲一下和task相关的知识,主要分一下几点:

1.activity的affinity(亲和力)

2.intent几种常见的flags

3.<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:

在android.content.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最好的宿主。下面我们会通过实例进行演示这个特性:

我们新建两个项目,分别命名为appa和appb,并且分别创建firstactivity和secondactivity,我们准备让appb中的firstactivity跳转到appa的secondactivity。appa中的secondactivity配置如下:

<activity android:name=".secondactivity"> 
   <intent-filter> 
    <action android:name="android.intent.action.app_a_second_activity" /> 
    <category android:name="android.intent.category.default" /> 
   </intent-filter> 
  </activity> 

然后,在appb中的firstactivity跳转代码如下:

intent intent = new intent("android.intent.action.app_a_second_activity"); 
startactivity(intent); 

我们要演示几个步骤:1.在appb中的firstactivity点击按钮跳转到appa中的secondactivity;2.按home键回到主屏,在主选单中再次启动appb;3.按home键回到主屏,在主选单中启动appa。演示过程如图所示:



再次启动appb应用:

启动appa应用:

我们发现在从appb跳转到appa的secondactivity之后,secondactivity实例好像是嵌入到了appb中,但是不影响appa的正常运行,这种关系如下图所示:

然后我们修改一下跳转的代码:

intent intent = new intent("android.intent.action.app_a_second_activity"); 
intent.setflags(intent.flag_activity_new_task); 
startactivity(intent); 

我们加上了flag_new_task标记,在来看一下演示结果:



再次启动appb:

启动appa:

我们看到差别了吧,当我们再次启动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()中。

下面我们来验证一下这个过程:

首先,activity启动模式都按照默认值“standard”。从firstactivity跳转到secondactivity,secondactivity实例如下:
从thirdactivity跳转到secondactivity时,跳转代码如下:

intent intent = new intent(this, secondactivity.class); 
intent.setflags(intent.flag_activity_clear_top); 
startactivity(intent); 

然后跳转后secondactivity实例如下:

从序列号可以看到这两个实例是不同的,证明它是经过了销毁和重新的过程。

然后我们把thirdactivity中的跳转代码添加flag_activity_single_top标记:

intent intent = new intent(this, secondactivity.class); 
intent.setflags(intent.flag_activity_clear_top | intent.flag_activity_single_top); 
startactivity(intent); 

两次实例均如下图所示:

如果我们不想添加flag_activity_single_top,那么把secondactivity的启动模式改为“standard”之外的三种即可,效果和上面一样,都不会创建新的实例。

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中加入此标记。

5.flag_activity_reset_task_if_needed:这个标记在以下情况下会生效:1.启动activity时创建新的task来放置activity实例;2.已存在的task被放置于前台。系统会根据affinity对指定的task进行重置操作,task会压入某些activity实例或移除某些activity实例。我们结合上面的clear_when_task_reset可以加深理解。

<activity>的task相关属性

在<activity>中定义了几个常见的task相关属性,它们分别代表了task内部不同的行为特征,我们就来逐个介绍一下:

1.android:allowtaskreparenting

这个属性用来标记一个activity实例在当前应用退居后台后,是否能从启动它的那个task移动到有共同affinity的task,“true”表示可以移动,“false”表示它必须呆在当前应用的task中,默认值为false。如果一个这个activity的<activity>元素没有设定此属性,设定在<application>上的此属性会对此activity起作用。例如在一个应用中要查看一个web页面,在启动系统浏览器activity后,这个activity实例和当前应用处于同一个task,当我们的应用退居后台之后用户再次从主选单中启动应用,此时这个activity实例将会重新宿主到browser应用的task内,在我们的应用中将不会再看到这个activity实例,而如果此时启动browser应用,就会发现,第一个界面就是我们刚才打开的web页面,证明了这个activity实例确实是宿主到了browser应用的task内。我们就来结合实例演示一下这个过程:

首先,在appb的firstactivity中,我们将跳转动作做以下改动:

intent viewintent = new intent(intent.action_view, uri.parse("http://www.google.com.hk")); 
startactivity(viewintent); 

进入appb时的界面:

启动web界面之后:

然后我们按home键,是当前应用退居后台,我们回到主选单,重新启动appb,界面如下:

此时我们在主选单中启动browser应用,出现在我们眼前的界面是这样的:

以上这种行为也证明了我们前面的论断,为了更清楚的说明问题,也为了让大家自己可以验证,下面我们要再次演示一下appb和appa的启动过程:

对于appa,在上面的基础上,不用修改其他地方,只需为secondactivity的<activity>元素添加一个属性,如下:

<activity android:name=".secondactivity" android:allowtaskreparenting="true"> 
... 
</activity> 

然后,在appb中的firstactivity跳转代码改为:

intent intent = new intent("android.intent.action.app_a_second_activity"); 
startactivity(intent); 

我们启动appb,看到一下界面:

然后点击按钮,跳转到appa中的secondactivity,界面如下:

此时appb中的firstactivity和appa中的secondactivity处于同一个task中taskid为28,然后我们按下home键,在主选单中再次启动appb,我们发现appa的secondactivity不见了,我们看到的是:

然后我们启动appa,这是我们不会看到它的firstactivity,而是看到了它的secondactivity:
通常两个应用分别有自己的task,它们的taskid肯定不同,但这里的secondactivity却显示taskid与appb相同,我们想一下也许就明白了,原来它是appb迁徙过来的,再启动appa时并未生成任何新的activity实例。这个时候如果我们按下后退键,appa就会立即退出,证明了此时appa的task里只有一个activity实例,也就是这个secondactivity实例。

需要注意的是,如果appb退居后台之后,没有再次启动appb,而是直接启动appa,将不会出现以上现象。重新宿主的动作发生在appb再次启动的过程中。

android:allowreparenting的效果图如下:

2.android:alwaysretaintaskstate

这个属性用来标记应用的task是否保持原来的状态,“true”表示总是保持,“false”表示不能够保证,默认为“false”。此属性只对task的根activity起作用,其他的activity都会被忽略。

默认情况下,如果一个应用在后台呆的太久例如30分钟,用户从主选单再次选择该应用时,系统就会对该应用的task进行清理,除了根activity,其他activity都会被清除出栈,但是如果在根activity中设置了此属性之后,用户再次启动应用时,仍然可以看到上一次操作的界面。

这个属性对于一些应用非常有用,例如browser应用程序,有很多状态,比如打开很多的tab,用户不想丢失这些状态,使用这个属性就极为恰当。

3.android:cleartaskonlaunch

这个属性用来标记是否从task清除除根activity之外的所有的activity,“true”表示清除,“false”表示不清除,默认为“false”。同样,这个属性也只对根activity起作用,其他的activity都会被忽略。

如果设置了这个属性为“true”,每次用户重新启动这个应用时,都只会看到根activity,task中的其他activity都会被清除出栈。如果我们的应用中引用到了其他应用的activity,这些activity设置了allowtaskreparenting属性为“true”,则它们会被重新宿主到有共同affinity的task中。

无图无真相,我们就来以实例演示一下这个过程,我们首先修改appb的根activity的<activity>元素,如下:

<activity android:name=".firstactivity" 
android:cleartaskonlaunch="true"> 
... 
</activity> 

fristactivity界面如下:

然后我们让firstactivity跳转到secondactivity,结果如下:

然后我们按home键回到主界面,再次启动appb,我们看到以下结果:
我们看到,再次启动appb时,我们只能看到firstactivity界面,此时在firstactivity之上的所有activity都已经被清除出栈。示意图如下:

4.android:finishontasklaunch

这个属性和android:allowreparenting属性相似,不同之处在于allowreparenting属性是重新宿主到有共同affinity的task中,而finishontasklaunch属性是销毁实例。如果这个属性和android:allowreparenting都设定为“true”,则这个属性胜出。

以上就是今天总结的内容,这些都是常用的知识,除此之外还有很多等着我们去探索,继续努力。

原文链接:http://blog.csdn.net/liuhe688/article/details/6761337

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网