Activity启动模式探究
文章目录
说到启动模式想必大家都很熟悉;
standard
,singleTop
,singleTask
,singleInstance
;要是说这几个有什么区别或者特点的话,估计有很多人也能说上来;但是,如果与taskAffinity
和Intent Activity Flag
配合使用的话,那情况就变的不一样了
在这之前,我们得先搞懂一些概念
tasks
这里的task不是对应用程序而言的,而是整个操作系统;我们可以简单的将task认为是一个任务栈,这个任务栈里面放的是我们启动的activity:
如图所示,当一个app调用另一个app的activity以后,他们可能会在同一个task里面,所以activity属于application;但是task是属于操作系统的;那么,怎么在手机中查看任务栈呢?
对于用户来说,只需要点击手机的menu键就可以了,如图所示:
对于我们开发人员来说,在查看任务栈的时候用adb就可以了:
adb shell dumpsys activity activities | sed -En -e '/Stack #/p' -e '/Running activities/,/Run #0/p'
接下来,我们还需要了解task的启动方式:新建
与恢复
- 新建其实就是在task中新建一个activity实例,比如在通知栏点击启动一个activity或者打开浏览器
- 恢复的话就是从activity从不可见到可见的过程,从task的角度来说,就是将activity调回到栈顶上;在恢复的时候,一般会走
onNewIntent
方法,并且还需要注意的是这个方法,只对startActivity
有效,对于从Navigation切换回来的时候是无效的;从启动模式上将的话,这个方法除了对standard无效之外,对其他都有效;换句话说,从Navigation切换或者是standrad模式启动的话,onNewIntent
是不走的
接下来我们将结合taskAffinity
, intent flag
来说明这四种启动模式
standard模式
这种模式相信很多人都知道,但是如果加上taskAffinity
, intent flag
情况就比较复杂了
从Launcher启动的情况
- 按返回键的情况
第一次的栈情况是这样的:
当我们按返回键退出重新进入的话,是这样的:
可以看到taskId从748变成了749,也就是说在返回的时候activity从748栈里面退出了,再次进入的话它会重新建一个749的task
startActivity的情况
一般来说这种方式的话, activity都会重新创建,但是加上taskAffinity
,intent flag设置为FLAG_ACTIVITY_NEW_TASK
启动之后,如果再启动它的话则不会重新创建,然后再启动一个一般的standard的activity的时候,它会将这个activity放到这个new task里面:
这个时候我如果再启动刚才带有flag 与affinity的StandardCActivity的时候就啥反应也没有了,它不会重新创建的也不会调回到栈顶的;
但是如果只是将StandardCActivity指定了affinity的话没有指定NEW_TASK
的话,那它还是会在原来的task里面重新创建
换句话说affinity只对new task有效
singleTop模式
如图所示,如果没有这个activity 并且没带new_task标记的话,就会在当前task的栈顶创建,如果带有new_task的标记的话就会新建一个task并创建activity,而且如果再启动一个standard模式的activity的话它会在new_task创建
singleTask
如图所示,如果栈中有这个实例的话,就移到栈顶,并将它上面的activity清空,但这里还有一点要注意下,如果当前的栈是一个new_task并且没有指定affinity的话,那当这个singletask的activity 第一次启动的时候会将它放到原来的task里面,并不会放到new_task里面,如图所示:
但是如果指定了与task2相同的affinity的话,那这个singleTask的activity就会在new_task里面创建,如图所示:
singleInstance
与 singleTask 相同,只是系统不会将任何其他 Activity 启动到包含实例的任务中。该 Activity 始终是其任务唯一仅有的成员;由此 Activity 启动的任何 Activity 均在单独的任务中打开。也就是有此种模式的 Activity 只能单独地位于一个任务栈中
Intent Flag介绍
Intent flag是为启动者准备的,比较常用的flag有FLAG_ACTIVITY_NEW_TASK
, FLAG_ACTIVITY_CLEAR_TASK
等,具体作用如图所示:
可以看到从task的创建到activity的返回,都可以根据flag设置不同的行为,需要注意的是FLAG_ACTIVITY_CLEAR_TASK
, TASK_ON_HOME
, EXCLUDE_FROM_RECENTS
, RETAIN_IN_RECENTS
这些flag只对新task有效
Task创建
- FLAG_ACTIVITY_NEW_TASK
设置了这个标志后,新启动的Activity并非就一定在新的Task中创建,如果A和B在属于同一个package,而且都是使用默认的Task Affinity,那B还是会在A的task中被创建。 所以,只有A和B的Task Affinity不同时,设置了这个标志才会使B被创建到新的Task。注意如果试图从非Activity的非正常途径启动一个Activity,比如从一个Receiver中启动一个Activity,则Intent必须要添加FLAG_ACTIVITY_NEW_TASK标记。 - FLAG_ACTIVITY_MULTIPLE_TASK
可以跟FLAG_ACTIVITY_MULTIPLE_TASK结合使用,当只用自己的时候相当于Manifast中android.R.attr.documentLaunchMode=”intoExisting”,当跟FLAG_ACTIVITY_MULTIPLE_TASK结合使用相当于 Manifast中android.R.attr.documentLaunchMode=”always” - FLAG_ACTIVITY_NEW_DOCUMENT
默认情况FLAG_ACTIVITY_NEW_DOCUMENT创建的document当用户关闭时之前tasks的entry会被remove掉,如果想保持在历史中一遍重新launch,就要用到这个flag.当使task的activity finish掉以后,历史entry将保持在界面以便用户重新打开类似*应用程序的历史。
确定了Task之后对它的操作
-
FLAG_ACTIVITY_CLEAR_TASK
如果Intent中设置了这个标志,会导致含有待启动Activity的Task在Activity被启动前清空。也就是说,这个Activity会成为一个新的root,并且所有旧的activity都被finish掉。这个标志只能与FLAG_ACTIVITY_NEW_TASK 一起使用。 -
FLAG_ACTIVITY_CLEAR_TOP
这个FLAG就相当于加载模式中的SingleTask,如果启动的Activity存在当前的栈中,系统会把要启动的Activity之上的Activity全部弹出栈空间,然后把Intent作为一个新的Intent传给这个Activity。 -
FLAG_ACTIVITY_SINGLE_TOP
这个FLAG就相当于加载模式中的singleTop,比如说原来栈中情况是A,B,C,D在D中启动D,栈中的情况还是A,B,C,D。 -
FLAG_ACTIVITY_REORDER_TO_FRONT
如果在intent里设置交给 startActivity(),这个flag会把已经运行过的acivity带到task历史栈的顶端。例如,一个task由A,B,C,D四个activity组成,如果D携带这个flag的intent调用startActivity()打开B,那么B就会被带到历史栈的前部,结果是:A,C,D,B.如果LAG_ACTIVITY_CLEAR_TOP 被设置,那么FLAG_ACTIVITY_REORDER_TO_FRONT将被忽略。
启动的标志设置
-
FLAG_ACTIVITY_NO_USER_ACTION
如果设置了这个标志,可以在避免用户离开当前Activity时回调到 onUserLeaveHint()。通常,Activity可以通过这个回调表明有明确的用户行为将当前Activity切出前台。这个回调标记了Activity生命周期中的一个恰当的点,可以用来“在用户看过通知之后”将它们清除,如闪烁LED灯。 -
FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
这个标志通常情况下不会通过应用的代码来设置,而是在通过最近任务启动activity时由系统设置的
启动的过程设置
- FLAG_ACTIVITY_NO_ANIMATION
禁用掉系统默认的Activity切换动画
返回的地方
- FLAG_ACTIVITY_TASK_ON_HOME
这个标志可以将一个新启动的任务置于当前的home任务(home activity task)之上(如果有的话)。也就是说,在任务中按back键总是会回到home界面,而不是回到他们之前看到的activity。这个标志只能与FLAG_ACTIVITY_NEW_TASK标志一起用 - FLAG_ACTIVITY_FORWARD_RESULT
就是 从 Activity A跳到B,再从B跳到C,并且希望 A中可以直接拿到C返回的结果,而B只是起到一个过渡的作用;Intent.FLAG_ACTIVITY_FORWARD_RESULT
这个flag 不能和startActivityForResult
一起使用,否则会报android.util.AndroidRuntimeException: FORWARD_RESULT_FLAG used while also requesting a result
需要说明的是从A->B需要调用startActivityForResult
, 而flag的添加是从B->C的
返回后的状态
-
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
如果设置这个标志,这个Activity就不会在近期任务中显示 -
FLAG_ACTIVITY_RETAIN_IN_RECENTS
默认情况下通过FLAG_ACTIVITY_NEW_DOCUMENT
启动的Activity在关闭之后,Task中的记录会相对应的
删除。如果为了能够重新启动这个Activity你想保留它,就可以使用这个flag,最近的记录将会保留在接口
中以便用户去重新启动。接受该Flag的Activity可以使用autoRemoveFromRecents
去复写这个request
或者调用Activity.finishAndRemoveTask( )方法。 -
FLAG_ACTIVITY_NO_HISTORY
用这个FLAG启动的Activity,一但退出,就不会存在于栈中。栈中是A,B,C 这个时候再C中以这个FLAG启动D的,D再启动E,这个时候栈中情况为A,B,C,E。简而言之,跳转到的activity不压在栈中
本文地址:https://blog.csdn.net/HuiMengNiTian/article/details/107897051