二、进阶之路
通过上面的介绍,我们对Android的task,back stack有了一定的了解,一般来讲,我们不用去关注activity是怎么被放入task的,以及在back stack的存储状态。但是,有时候我们也会有一些特殊的需求。比如说,在一个新的activity启动时,我们想把它放进一个新的task中;或者启动一个activity时,我们不希望创建一个新的实例,而是使用task中已有的该activity的实例;又或者我们希望在启动一个activity时,将task中原有的activity全都销毁等等。所有的这些都可以通过使用manifest 中<activity>标签的属性以及startactivity时intent所带的flag来实现。通过它们,我们可以组合出我们想要的功能,对task进行有效的管理。
activity标签关于task的属性有:
参考:http://developer.android.com/guide/topics/manifest/activity-element.html
intent的flag有:
FLAG_ACTIVITY_BROUGHT_TO_FRONT
FLAG_ACTIVITY_CLEAR_TASK
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_SINGLE_TOP
FLAG_ACTIVITY_MULTIPLE_TASK等
参考: http://developer.android.com/reference/android/content/Intent.html
launch mode:
launch mode 决定了activity在task中是如何被实例化的,是管理task的核心所在。我们既可以通过manifest 中activity属性来控制,也可以在start activity时,使用intent flags 来控制;当两者都有时,以manifest文件为准。
launch mode 有四个值:
"standard"
"singleTop"
"singleTask"
"singleInstance"
这是它们的一个对比表格:
standard: android 默认的方式。为每一个启动的activity实例化,并放入back stack 中,并将intent指向它。
singleTop:当启动一个activity时,如果该activity已经有一个实例在back stack的顶部,那么将会用onnewintent方法启动该activity而不会创建一个新的实例;如果该activity实例不在back stack顶部或不存在,则依然会创建新的实例。下面是一个demo:
<activity android:name=".activity.Activity_3" android:launchMode="singleTop"> </activity>
public class Activity_3 extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent=new Intent(this,Activity_3.class); startActivity(intent); showRunningTasks(); } }
与初步了解中的activity启动顺序一致,activity1启动activity2,activity2启动activity3,设置activity3为singleTop,并由activity3启动activity3
结果如上图,stack中只有三个activity,activity3并没有实例化一个新的对象。若是activity3改为standard,则会实例化一个新的对象,调用oncreate方法,按照上面的代码会陷入不断启动activity3的死循环中,囧,结果就不贴了~
singleTask:当task中没有该activity实例时,系统会在开启一个新的task,并且实例化该activity作为root activity;当task中存在该activity实例时,会调用activity的onnewintent方法,并不会创建一个新的实例。也就是说一个task中只会存在该activity的一个实例。下面是一个demo:
<activity android:name=".activity.Activity_3" android:launchMode="singleTask"> </activity>将activity3设置为singleTask,并且activity1启动activity2,activity2启动activity3,结果:
细心的同学就发现问题了,不是新开一个task么,怎么activity3还在原先的task呢,这个问题[1]稍后会说。下面测试一下task中已经有实例的情况:
activity1启动activity2,activity2启动activity3,activity3启动activity1;activity1设为singleTask。结果:
activity1并没有重新创建一个新的实例,而是回到已有的实例中,而且activity1上面的activity2,activity3将会被销毁,将activity1置于栈顶。最后的task如上图右所示。
singleInstance:跟singleTask基本一致,除了一点:当activity设置为singleInstance时,其所在的task不会再放入其他activity。该activity是task中唯一的成员,由其启动的activity将会放入其他task中。demo如下:
activity1启动activity2,activity2启动activity3,activity3启动activity1;activity1设为singleInstance。结果:
activity1在一个task中,而activity2,activity3放入了一个新的task中。activity3启动activity1时,会回到id=600的task,不会创建新的实例。
taskAffinity:
默认同一个应用中的activity属于一个task,taskAffinity决定了activity倾向于属于哪个task。通过设置taskAffinity的值,可以让activity属于特定的task。默认的值为应用的包名。taskAffinity主要有两个方面的应用:
1、带有FLAG_ACTIVITY_NEW_TASK的intent会产生一个新的task启动activity,这个task会根据taskAffinity的值来产生,如果已经有一个taskAffinity相同的task,则会将activity放入这个task,不再产生新的task。所以说FLAG_ACTIVITY_NEW_TASK不是一定会产生新的task的,取决于taskAffinity的值。不知道大家记得没,在singleTask的测试时,我们也遇到了这种情况(问题[1]),文档中说会产生新的task,但是没有产生,就是因为taskAffinity的值是一样的。所以说,要产生新的task,记得要改taskAffinity的值哦。
2、 allowTaskReparenting 设置为"true时。这种情况下,当一个askAffinity值相同的task进入前台时,activity会从当前的task转移到该taskAffinity值相同的task中。
Intent Flags
FLAG_ACTIVITY_NEW_TASK:在新的task中启动activity;如果已经有一个task包括该activity实例,那么会将该task进入前台,调用onnewintent启动该activity。
这个与launchMode的singleTask行为一致。 (官方文档时这样说的,但是我测试发现不是这样,activity是要创建的。大家可以讨论一下这里。但是这个属性可以将后台的taskAffinity值相同的task进入前台)
FLAG_ACTIVITY_SINGLE_TOP:作用与launchMode的singleTop一样。
FLAG_ACTIVITY_CLEAR_TOP:如果activity在当前task中运行,back stack中所有在它之上的activity将会被销毁,使得该activity处于栈顶,而不会重新创建一个新的实例。
测试时发现该activity却是重建的,这样使用:intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);才不会create,而是调用onnewintent。
FLAG_ACTIVITY_CLEAR_TOP经常与FLAG_ACTIVITY_NEW_TASK合用:这样的话,可以启动一个task中的root activity,该task会进入前台,而且只剩下root activity,产生了启动的效果。调用方式:intent.addFlags(FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP)
FLAG_ACTIVITY_MULTIPLE_TASK:与FLAG_ACTIVITY_NEW_TASK合用,不管是什么情况下,都会产生一个新的task,而不会尝试去寻找一个askAffinity值相同的task。
FLAG_ACTIVITY_BROUGHT_TO_FRONT:launch mode 为 singleTask时,系统会设置该值,自己无需设置。
其他属性:
alwaysRetainTaskState:当应用的root activity 设置为TRUE时,经过长时间后,task的back stack状态将会保持下去,不会清除。
clearTaskOnLaunch:当应用的root activity 设置为TRUE时,后台恢复时,清空back stack,只剩下root activity。与alwaysRetainTaskState作用相反。
finishOnTaskLaunch:与clearTaskOnLaunch作用相似,只不过只是清除该单个activity。当task重新进入前台时,该activity不再展示。