任务栈 Activity的启动模式 Intent中的Flag taskAffinity
Posted 白乾涛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了任务栈 Activity的启动模式 Intent中的Flag taskAffinity相关的知识,希望对你有一定的参考价值。
关于任务栈Task
栈的概念栈(Stack)是一种常用的数据结构,栈只允许访问栈顶的元素,栈就像一个杯子,每次都只能取杯子顶上的东西,而对于栈就只能每次访问它的栈顶元素,从而可以达到保护栈顶元素以下的其他元素.”先进后出”或”后进先出”就是栈的一大特点,先进入栈的元素总是要等到后进入栈的元素出栈以后才能出栈.递归就是利用到了系统栈,暂时保存临时结果,对临时结果进行保护.栈的基本操作:压栈、弹栈任务栈Task简单的就是一组以栈的模式聚集在一起的Activity组件集合,类似于一个填充了Activity的容器,最先加入的Activity会处于容器最下面,最后加入的处于容器最上面,而从Task中取出Activity时是从最顶端先取出,最后取出的是最开始添加Activity,这就是后进先出模式,而Activity在Task中的顺序是可以控制的,在Activity跳转时用到Intent Flag可以设置新建activity的创建方式。
Activity的启动模式
Activity启动模式有四种,可以根据实际的需求为Activity设置对应的启动模式,从而可以避免创建大量重复的Activity等问题。设置Activity的启动模式,只需要在androidManifest.xml里对应的<activity>标签设置Android:launchMode属性。standard默认模式,可以不用写配置。在这个模式下,都会默认创建一个新的实例。因此,在这种模式下,可以有多个相同的实例,也允许多个相同Activity叠加。例如:若我有一个Activity名为A1, 上面有一个按钮可跳转到A1。那么如果我点击按钮,便会新启一个Activity A1叠在刚才的A1之上,再点击,又会再新启一个在它之上。点back键会依照栈顺序依次退出。singleTop可以有多个实例,但是不允许多个相同Activity叠加。即,如果Activity在栈顶的时候,启动相同的Activity,不会创建新的实例,而会调用其onNewIntent方法。singleTask只有一个实例。如果在同一个应用程序中启动它,若Activity不存在,则会在当前task创建一个新的实例,若存在,则会把task中在其之上的其它Activity destory掉并调用它的onNewIntent方法。如果是在别的应用程序中启动它,则会新建一个task,并在该task中启动这个Activity。singleTask允许别的Activity与其在一个task中共存,也就是说,如果我在这个singleTask的实例中再打开新的Activity,这个新的Activity还是会在singleTask的实例的task中。可以使用singleTask来退出整个应用。将主Activity设为SingTask模式,然后在要退出的Activity中转到主Activity,然后重写主Activity的onNewIntent函数,并在函数中加上一句finish。singleInstance只有一个实例,并且这个实例独立运行在一个task中,这个task只有这个实例,不允许有别的Activity存在。
Intent中常用的Flag
Flag表示Intent的标志位,常用于Activity的场景中,它和Activity的启动模式有着密切的联系。下面列举的是和Activity启动模式相关的Flag属性:Intent.FLAG_ACTIVITY_NEW_TASK系统会检查当前所有已创建的Task中是否有该要启动的Activity的Task,若有,则在该Task上创建Activity;若没有则新建具有该Activity属性的Task,并在该新建的Task上创建Activity。FLAG_ACTIVITY_SINGLE_TOP这个FLAG就相当于启动模式中的singletop比如说原来栈中情况是ABCD,在D中启动D,栈中的情况还是ABCDFLAG_ACTIVITY_CLEAR_TOP这个FLAG就相当于启动模式中的SingleTask,这种FLAG启动的Activity会把要启动的Activity之上的Activity全部弹出栈空间。比如:原来栈中的情况是ABCD,这个时候从D中跳转到B,这个时候栈中的情况就是AB了FLAG_ACTIVITY_NO_HISTORY这个标记顾名思义意思就是说,用这个FLAG启动的Activity,一旦【不可见】,他就不会存在于任务栈中。比如,原来是ABC,这个时候在C中以这个FLAG启动D的 ,D再启动E,这个时候栈中情况为ABCE。FLAG_ACTIVITY_BROUGHT_TO_FRONT比方说我现在在A中启动B,启动时在A中的Intent加上这个标记,此时在B中再启动CD(正常启动CD),此时栈的情况是ABCD。如果这个时候在D中再启动B,这个时候栈的情况是 ACDB。特别注意的是,我上面说的网上人描述的这个FLAG,会很容易让人误解成这样,A,B,C,D都是标准加载,然后我在D中启动A,这个intent加上FLAG_ACTIVITY_BROUGHT_TO_FRONT ,就会误认为变成B,C,D,A!!其实不是,这个时候应该是A,B,C,D,A.不信的人大家试试看。不过下面这个标记和这个标记就会让大家明白了!FLAG_ACTIVITY_REORDER_TO_FRONT就按在 Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT 最后说的,如果在A,B,C,D正常启动的话,不管B有没有用FLAG_ACTIVITY_BROUGHT_TO_FRONT启动,此时在D中启动B的话,还是会变成A,C,D,B的。FLAG_ACTIVITY_RESET_TASK_IF_NEEDED这个也不知道具体怎么用,看文档有点象开辟新的Task,不过测试完,不像那么简单。FLAG_ACTIVITY_NO_USER_ACTIONonUserLeaveHint()作为activity周期的一部分,它在activity因为用户要跳转到别的activity而要退到background时使用。比如,在用户按下Home键(用户的choice),它将被调用。比如有电话进来(不属于用户的choice),它就不会被调用。那么系统如何区分让当前activity退到background时使用是用户的choice?它是根据促使当前activity退到background的那个新启动的Activity的Intent里是否有 FLAG_ACTIVITY_NO_USER_ACTION来确定的。注意:通过调用finish()使该activity销毁时不会调用该函数
Intent中所有定义的Flag
FLAG_GRANT_READ_URI_PERMISSION //FLAG_GRANT_WRITE_URI_PERMISSION //FLAG_FROM_BACKGROUND //FLAG_DEBUG_LOG_RESOLUTION //FLAG_EXCLUDE_STOPPED_PACKAGES //FLAG_INCLUDE_STOPPED_PACKAGES //FLAG_ACTIVITY_NO_HISTORY //退出后不会存在于任务栈中FLAG_ACTIVITY_SINGLE_TOP //单一顶部FLAG_ACTIVITY_NEW_TASK //在新任务栈中打开FLAG_ACTIVITY_MULTIPLE_TASK //FLAG_ACTIVITY_CLEAR_TOP //若此Activity已存在于任务栈中,再次启动时弹出它所有顶部的ActivityFLAG_ACTIVITY_FORWARD_RESULT //FLAG_ACTIVITY_PREVIOUS_IS_TOP //FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS //FLAG_ACTIVITY_BROUGHT_TO_FRONT //FLAG_ACTIVITY_RESET_TASK_IF_NEEDED //FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY //FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET //FLAG_ACTIVITY_NO_USER_ACTION //FLAG_ACTIVITY_REORDER_TO_FRONT //FLAG_ACTIVITY_NO_ANIMATION //FLAG_ACTIVITY_CLEAR_TASK //FLAG_ACTIVITY_TASK_ON_HOME //FLAG_RECEIVER_REGISTERED_ONLY //FLAG_RECEIVER_REPLACE_PENDING //FLAG_RECEIVER_FOREGROUND //FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT //FLAG_RECEIVER_BOOT_UPGRADE //
关于taskAffinity属性
清单文件中,activity 的属性android:allowTaskReparenting用于设定:Activity是否能够从启动它的任务栈中转移到另一个与启动它的任务栈有相同taskAffinity属性值的任务栈中,转移时机是在另一个任务栈被带到前台的时候。如果设置为true,则能够转移,如果设置了false,则这个Activity必须要保留在启动它的那个任务栈中。实验1、新建两个工程,App1和App2App1和App2都设置android:taskAffinity="aaa.aaa"android:allowTaskReparenting="true"先运行App1,然后点击home键,让App1运行在后台再运行App2,会发现这时显示的是App1的mainActivity,并且长按home键,会发现运行过的程序只有App1。2、紧接着又在此基础上做了另外一个实验在App1上新建一个secondActivity,设置android:taskAffinity="aaa.bbb"android:allowTaskReparenting="true"在mainActivity中startActivity时,设置Intent中flag属性为FLAG_ACTIVITY_NEW_TASK,注意,这里的flag属性必须为newtask。然后运行App1,点击进入secondActivity,这时长按home键,会发现运行过的程序中有两个App1,并且一个显示的是mainActivity另一个显示的是secondActivity。这时点击home键,让程序回到后台然后运行App2,会发现这时显示的是App1的mainActivity,此时点击返回会直接返回home。注意,虽然此时App1的mainActivity被finish了,但App1的secondActivity还在后台等着呢。同样,长按home键,会发现运行过的程序只有App1的两个任务栈,并没有App2。3、在此基础上堆App1再次修改在App1上新建一个thirdActivity,设置属性android:taskAffinity="aaa.aaa"android:allowTaskReparenting="true"并在secondActivity中startActivity时,设置Intent中flag属性为FLAG_ACTIVITY_NEW_TASK;运行App1,点击进入secondActivity,再进入thirdActivity,此时长按home键,会发现运行过的程序中有两个App1,并且一个显示的是secondActivity另一个显示的是thirdActivity。此时点击返回,会回到mainActivity,再点击返回,会回到secondActivity,再点击返回,回到home页面。以上实验中,如果startActivity时不设置Intent中flag属性为FLAG_ACTIVITY_NEW_TASK,则若先启动的是App1,那么不管是App1中的Activity还是App2中的mainActivity,都是运行App1的一个任务栈中。
以上是关于任务栈 Activity的启动模式 Intent中的Flag taskAffinity的主要内容,如果未能解决你的问题,请参考以下文章
任务栈 Activity的启动模式 Intent中的Flag taskAffinity