Activity启动模式对于广大的Android开发者来说是最基本的知识了,可是你的了解全面了么?下面我就带领大家复习下Activity的启动模式,寻找那些容易被忽视的点。
standard
默认。系统在启动 Activity 的任务中创建 Activity 的新实例并向其传送 Intent。Activity 可以多次实例化,而每个实例均可属于不同的任务,并且一个任务可以拥有多个实例。
singleTop
如果当前任务的顶部已存在 Activity 的一个实例,则系统会通过调用该实例的 onNewIntent() 方法向其传送 Intent,而不是创建 Activity 的新实例。Activity 可以多次实例化,而每个实例均可属于不同的任务,并且一个任务可以拥有多个实例(但前提是位于返回栈顶部的 Activity 并不是 Activity 的现有实例)。
一个Activity 的“ standard ”或“ singleTop “启动模式的共同特点就是:可以多次实例化,实例可以属于任何任务(task)并且可以位于Activity 栈的任何地方。
singleTask:
系统创建新任务并实例化位于新任务底部的 Activity。但是,如果该 Activity 的一个实例已存在于一个单独的任务中,则系统会通过调用现有实例的 onNewIntent() 方法向其传送 Intent,而不是创建新实例。同一个任务栈中只能存在一个对应的 Activity 实例。
注:尽管 Activity 在新任务中启动,但是用户按“返回”按钮仍会返回到前一个 Activity。
若B设置为singleTask,A->B->C->D->E->B此时栈中只有AB两个实例对象,C,D,E均被销毁,singleTask有CLEAR_TOP的效果,从距离原先的B实例最近的Activity开始移除,C->D->E。
与此同时E跳转到B时,会直接执行B的onNewIntent(Intent)方法,B不再执行从onCreate开始的完整生命周期。
特别注意:
在4.x和之前的系统下,A1(startActivityForResult)->A2(singleTask, startActivityForResult)->A3->A4,当A1打开A2之后会立即回调onActivityResult()函数,A2打开A3仍然可以正常回调onActivityResult();但是从5.0开始,A1打开A2的时候 onActivityResult() 函数也能正常的回调,不会立即回调。
在5.0以下使用startActivityForResult,设置的目标Activity的启动模式不能为singleTask和singleInstance,如果设置为这两种,当前Activity的onActivityResult方法会立即执行,并且接收到一个cancel result的结果,接收到的参数都是空,不是我们想要的结果。
5.0以上使用startActivityForResult,即使目标Activity设置为singletask和singleInstance时,每次跳转都会生成新的Activity。因为startActivityForResult需要返回值, 会保留实例, 覆盖单例效果.
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
常用的标志位:
FLAG_ACTIVITY_NEW_TASK: 同singleTask启动模式.
FLAG_ACTIVITY_SINGLE_TOP: 同singleTop启动模式.
FLAG_ACTIVITY_CLEAR_TOP: 一般和singleTask启动模式出现. 如果是singleTask启动模式, 会清除栈上其他实例, 复用实例, 调用onNewIntent; 如果是standard启动模式, 即默认模式, 则会清除自己和其他实例, 并重新创建, 调用 onCreate。
A->B->C->D->E->B时,E跳转时设置FLAG_ACTIVITY_CLEAR_TOP,B为标准启动模式,则会清除BCDE同时会创建一个新的B实例;若B为singletask则会保留之前的B的实例,不会再新增B的实例。
singleInstance
与 “singleTask” 相同,只是系统不会将任何其他 Activity 启动到已经包含实例了的任务中。该 Activity 始终是其任务唯一仅有的成员;由此 Activity 启动的任何 Activity 均在单独的任务中打开。它拥有一个单独的任务栈。
特别注意:
1.A1->A2(SingleInstance),摁下 Home 键之后,点击应用图标再次进入应用,返回的是 A1 页面,这是因为 A2 在另一个单独的 Activity task 栈中,点击图标返回的是主 Activity 栈,所以此时显示的 A1 页面,而不是 A2 页面。但是如果从最近任务栏中进入,则返回的依旧还是A2页面。
2.注意singleInstance的返回键的处理和上面3个 mode 有区别,如果是使用正常的 startActivity 进行的启动,启动顺序A1->A2->A3(singleInstance)->A4,在A4页面摁下back键,返回的是A2,再返回A1,接着再次摁下back键,返回的才是A3;如果是使用 startActivityForResult 启动的,在4.x和之前的系统下,表现和之前是一样的,但是在5.0开始,A1->A2-A3(singleInstance + startActivityForResult)->A4,在A4摁下返回键,返回的是A3->A2->A1,这个需要着重说明一下。
3.在4.x和之前的系统下,A1(startActivityForResult)->A2(singleInstance, startActivityForResult)->A3->A4,当A1打开A2之后会立即回调onActivityResult()函数,A2打开A3也会立即回调onActivityResult()函数,与singleTask相比较,A3也会受到影响;但是从5.0开始,A1打开A2和A2打开A3的两种情况下 onActivityResult() 函数都能正常的回调,不会立即回调。
相比之下,“ singleTask ”和“ singleInstance ”启动模式的activity 只能启动在一个任务中。 他们总是在activity栈的顶部。 此外,该设备仅维持一次并且仅一个activity的实例–仅在一样的任务中。
A standard B singleTask;执行A--B--A --B的跳转,结果:
直接用startActivity,栈中都是AB(执行onNewIntent);
用startActivityForResult的结果:
5.0以及以上,栈中内容:ABAB;
5.0以下,栈中内容:AB(执行onNewIntent)
taskAffinity
每个Activity都有taskAffinity属性,这个属性指出了它希望进入的Task。如果一个Activity没有显式的指明该 Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果 Application也没有指明,那么该taskAffinity的值就等于包名。而Task也有自己的affinity属性,它的值等于它的根 Activity的taskAffinity的值。
taskAffinity命名必须至少包含一个“.”,英文的点,同时需要注意,taskAffinity只在singleTask和singleInstance模式中生效,同时必须是通过startActivity进行跳转,使用startActivityForResult()跳转,taskAffinity在5.0以上是不生效。