一、首先,复习一下Activity的四种启动模式:
1、standard:标准模式,每次跳转都会创建一个新的Activity实例;
2、singleTop:跳转时检查当前Activity栈,判断栈顶是否有对应Activity的实例,若有则跳转到已有的Activity,直接调用onNewIntent方法;若无,则创建一个新的Activity实例。
例:MainActivity—> AaActivity —> AaActivity —> AaActivity AaActivity启动模式为singTop
栈中Activity的顺序是 MainActivity、AaActivity
3、singleTask:跳转时检查当前Activity栈,判断栈中是否有对应Activity的实例, 若有则跳转到已有的 Activity,直接调用onNewIntent方法,并移除位于该栈中位于该Activity 上方的其它Activity;若无,则在栈顶创建一个新的Activity实例。
例:MainActivity—> AaActivity —> BbActivity —> CcActivity—> AaActivity AaActivity启动模式为singTask
栈中Activity的顺序是 MainActivity、AaActivity
4、singInstance:加载该Activity时如果没有实例化,会创建一个新的任务栈,实例化入栈,如果已经存在,直接调用onNewIntent,该Activity的栈中不允许启动其他的Activity,从该Activity启动的其他Activity都将放到其他的任务栈中。如果应用中没有存在的栈,则会新建一个。
例:MainActivity—> AaActivity —> BbActivity —> CcActivity —> AaActivity AaActivity启动模式为singleInstance
按返回键退栈的顺序是 AaActivity —> CcActivity —> BbActivity —> MainActivity
二、Intent的Flag属性
学习Flag属性时,先了解一下 Activity的taskAffinity属性。 taskAffinity定义了Activity的归属,也就是Activity应该在哪个Task中,Activity与Task的吸附关系。如果一个Activity没有显式的指明该 Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果 Application也没有指明,那么该taskAffinity的值就等于包名。而Task也有自己的affinity属性,它的值等于它的根 Activity的taskAffinity的值。
affinity的应用场景:
1.根据affinity重新为Activity选择宿主task(与allowTaskReparenting属性配合工作);
2.启动一个Activity过程中Intent使用了FLAG_ACTIVITY_NEW_TASK标记,根据affinity查找或创建一个新的具有对应 affinity的task。
常见的Flag:---------------------------- 看的再多,不如亲测 ----------------------------
1、FLAG_ACTIVITY_NEW_TASK
如果同一个应用中Activity的taskAffinity都使用默认值或都设置相同值时,应用内的Activity之间的跳转使用这个标记是没有意义的
如果Activity定义了taskAfiinity属性,并且allowTaskReparenting = true时,
1)不添加Flag,无论task中是否已经有Activity的实例,都是标准启动,跳转到一个新的Activity实例,不会创建新task
2)添加Flag,根据affinity查找是否有对应的task,
如果没有,则创建一个task并入栈,从该Activity直接跳转的Activity默认也在该task中;
如果已经存在,并且Activity已存在为当前所在task的根Activity,则不会执行跳转,除非同FLAG_ACTIVITY_CLEAR_TASK一同使用,则可以跳转(测试结果)
如果不是在该反之则会根据其taskAffinity属性查找或创建一个task进行跳转,并创建新的实例。
下图,AaActivity定义了taskAffinity,Main跳转到Aa时添加FLAG_ACTIVITY_NEW_TASK,创建一个新的task,然而从Cc 再点击跳转到 Aa,点击无反应。
<activity android:name=".AaActivity" android:screenOrientation="portrait" android:allowTaskReparenting="true" android:taskAffinity="com.xmy.intenttest">
3)两个不同affinity属性的task,通过Activity跳转相互切换,定义了affnity属性的task只能通过栈顶的Activity进行跳转
如下图:Main跳转到Aa时添加FLAG_ACTIVITY_NEW_TASK,创建一个新的task,然而从Cc 再点击跳转到 Main,再点击Main跳转Aa,结果是跳转到了CcActivity,且到达该类,只调用了OnResume方法。
2、FLAG_ACTIVITY_CLEAR_TOP
1、当Intent对象包含这个标记时,如果在栈中发现存在Activity实例,则清空这个实例之上的Activity,使其处于栈顶。
2、在目标Activity使用默认的“standard”启动模式下,如果没有在Intent使用到FLAG_ACTIVITY_SINGLE_TOP标记,那么目标
Activity将关闭后重建;
3、如果使用了FLAG_ACTIVITY_SINGLE_TOP(intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);)
标记,或者目标Activity定义为singTop启动模式,则会使用已存在的实例,调用onNewIntent(),相当于singleTask;
4、对于singleTask、singleInstance启动模式,都将使用已存在的实例,Intent会被传递到这个实例的onNewIntent()方法中。
下图:AaActivity使用默认的“standard”启动模式,Main—>Aa—>Bb—>Cc —(FLAG_ACTIVITY_CLEAR_TOP)—> Aa,
最后一步,会销毁掉AaActivity上方的所有Activity,并且AaActivity被销毁重建。
3、FLAG_ACTIVITY_SINGLE_TOP
单独使用,与启动模式singleTop效果完全相同
与上例中FLAG_ACTIVITY_CLEAR_TOP一同使用,和启动模式singleTask效果相同
4、FLAG_ACTIVITY_BROUGHT_TO_FRONT
这个网上很多人是这样写的。如果activity在task存在,拿到最顶端,不会启动新的Activity。 NO!NO!NO!亲测,只会启动一个新的Activity!
还有这样写的:比方说我现在有A,在A中启动B,此时在A中Intent中加上这个标记。此时B就是以 FLAG_ACTIVITY_BROUGHT_TO_FRONT 这个启动的,此时在B中再启动C,D,如果这个时候在D中再启动B,这个时候最后的栈的情况是 A,C,D,B. NO!NO!NO!亲测,只会启动一个新的Activity!
/** * This flag is not normally set by application code, but set for you by * the system as described in the * {@link android.R.styleable#AndroidManifestActivity_launchMode * launchMode} documentation for the singleTask mode. */ public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 0x00400000;
源码中是酱婶解释的,这个标志一般不是在程序代码中设置的,而是在配置文件中设置launchModel为singleTask时系统帮你设置的。
这个Flag的作用是重新创建一个新的Activity(即便堆栈中已经存在这个Activity),并提到栈顶。
所以,对于我们代码中设置没有实际意义。
5、FLAG_ACTIVITY_REORDER_TO_FRONT
注意了,这个才是:如果activity在task存在,拿到最顶端,Intent会传递到onNewIntent()方法,不会启动新的Activity。
下图,启动顺序Main—>Aa—>Bb—Cc—>Aa, 最后一步Intent添加FLAG_ACTIVITY_REORDER_TO_FRONT。
原来栈内顺序:Main、Aa、Bb、Cc,最后一步跳转后栈中顺序:Main、Bb、Cc、Aa
6、FLAG_ACTIVITY_NO_HISTORY
/** * If set, the new activity is not kept in the history stack. As soon as * the user navigates away from it, the activity is finished. This may also * be set with the {@link android.R.styleable#AndroidManifestActivity_noHistory * noHistory} attribute. * * <p>If set, {@link android.app.Activity#onActivityResult onActivityResult()} * is never invoked when the current activity starts a new activity which * sets a result and finishes. */ public static final int FLAG_ACTIVITY_NO_HISTORY = 0x40000000;
源码解释:如果设置该Flag,新创建的Activity将不会保存在栈里,当用户返回时,该页面是被销毁掉的。这个属性也可以在配置文件中设置。如果设置该Flag,即使新建的Activity设置结果回调,上一个Activity中的onActivityResult()方法也永远不会调用
7、FLAG_ACTIVITY_NO_ANIMATION
这个厉害了,设置两个Activity切换没有任何动画效果,无缝连接。
三、Intent的其他属性以及使用
那啥,intent是很基础的知识,网络上有很多很多文章,写的也很详细。