欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Activity启动模式探究

程序员文章站 2022-03-21 22:18:55
文章目录tasksstandard模式从Launcher启动的情况startActivity的情况singleTop模式singleTasksingleInstanceIntent Flag介绍Task创建确定了Task之后对它的操作启动的标志设置启动的过程设置返回的地方返回后的状态说到启动模式想必大家都很熟悉;standard, singleTop, singleTask, singleInstance;要是说这几个有什么区别或者特点的话,估计有很多人也能说上来;但是,如果与taskAffinity和...

说到启动模式想必大家都很熟悉;standard, singleTop, singleTask, singleInstance;要是说这几个有什么区别或者特点的话,估计有很多人也能说上来;但是,如果与taskAffinityIntent Activity Flag配合使用的话,那情况就变的不一样了

在这之前,我们得先搞懂一些概念

tasks

这里的task不是对应用程序而言的,而是整个操作系统;我们可以简单的将task认为是一个任务栈,这个任务栈里面放的是我们启动的activity:
Activity启动模式探究
如图所示,当一个app调用另一个app的activity以后,他们可能会在同一个task里面,所以activity属于application;但是task是属于操作系统的;那么,怎么在手机中查看任务栈呢?
对于用户来说,只需要点击手机的menu键就可以了,如图所示:
Activity启动模式探究

对于我们开发人员来说,在查看任务栈的时候用adb就可以了:

adb shell dumpsys activity activities | sed -En -e '/Stack #/p' -e '/Running activities/,/Run #0/p'

Activity启动模式探究
接下来,我们还需要了解task的启动方式:新建恢复

  • 新建其实就是在task中新建一个activity实例,比如在通知栏点击启动一个activity或者打开浏览器
  • 恢复的话就是从activity从不可见到可见的过程,从task的角度来说,就是将activity调回到栈顶上;在恢复的时候,一般会走onNewIntent方法,并且还需要注意的是这个方法,只对startActivity有效,对于从Navigation切换回来的时候是无效的;从启动模式上将的话,这个方法除了对standard无效之外,对其他都有效;换句话说,从Navigation切换或者是standrad模式启动的话,onNewIntent是不走的

接下来我们将结合taskAffinity, intent flag来说明这四种启动模式

standard模式

这种模式相信很多人都知道,但是如果加上taskAffinity, intent flag情况就比较复杂了

从Launcher启动的情况

  • 按返回键的情况
    第一次的栈情况是这样的:
    Activity启动模式探究
    当我们按返回键退出重新进入的话,是这样的:
    Activity启动模式探究
    可以看到taskId从748变成了749,也就是说在返回的时候activity从748栈里面退出了,再次进入的话它会重新建一个749的task

startActivity的情况

一般来说这种方式的话, activity都会重新创建,但是加上taskAffinity,intent flag设置为FLAG_ACTIVITY_NEW_TASK启动之后,如果再启动它的话则不会重新创建,然后再启动一个一般的standard的activity的时候,它会将这个activity放到这个new task里面:
Activity启动模式探究
这个时候我如果再启动刚才带有flag 与affinity的StandardCActivity的时候就啥反应也没有了,它不会重新创建的也不会调回到栈顶的;
但是如果只是将StandardCActivity指定了affinity的话没有指定NEW_TASK的话,那它还是会在原来的task里面重新创建
Activity启动模式探究

换句话说affinity只对new task有效

singleTop模式

Activity启动模式探究
如图所示,如果没有这个activity 并且没带new_task标记的话,就会在当前task的栈顶创建,如果带有new_task的标记的话就会新建一个task并创建activity,而且如果再启动一个standard模式的activity的话它会在new_task创建

singleTask

Activity启动模式探究
如图所示,如果栈中有这个实例的话,就移到栈顶,并将它上面的activity清空,但这里还有一点要注意下,如果当前的栈是一个new_task并且没有指定affinity的话,那当这个singletask的activity 第一次启动的时候会将它放到原来的task里面,并不会放到new_task里面,如图所示:
Activity启动模式探究
但是如果指定了与task2相同的affinity的话,那这个singleTask的activity就会在new_task里面创建,如图所示:
Activity启动模式探究

singleInstance

与 singleTask 相同,只是系统不会将任何其他 Activity 启动到包含实例的任务中。该 Activity 始终是其任务唯一仅有的成员;由此 Activity 启动的任何 Activity 均在单独的任务中打开。也就是有此种模式的 Activity 只能单独地位于一个任务栈中

Intent Flag介绍

Intent flag是为启动者准备的,比较常用的flag有FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_CLEAR_TASK等,具体作用如图所示:
Activity启动模式探究
可以看到从task的创建到activity的返回,都可以根据flag设置不同的行为,需要注意的是FLAG_ACTIVITY_CLEAR_TASKTASK_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不压在栈中


演示demo下载地址

本文地址:https://blog.csdn.net/HuiMengNiTian/article/details/107897051