Activity的启动模式全解standard,singleTop,singleTask,singleInstance

在android中控制Activity的启动模式的属性主要控制两大功能:

1,控制activity 进入哪一个任务task 中,   有两种可能,进入启动task中,进入指定taskAffinity的task中,如果指定taskAffinity的task还不存在,则创建一个

2,控制activity 多次启动的处理模式,       有三种可能,每次都创建新的,如果在顶部不创建新的,  如果存在则清除之上所有的activity

 

activity的taskAffinity属性值默认为application的taskAffinity属性值,application的taskAffinity属性值默认为包名 

手动设置taskAffinity属性值时,可以设置任意字符串但是必须包含至少一个'.'点符号,否则apk会在安装时解析包错误

Activity的启动模式中多次启动的处理模式要先确定activity进入的task

activity 的launchMode 静态设置时有四种模式,动态设置(intent flag)时常用的有三种 ,其中让taskAffinity属性起作用的有两种模式 singleTaskFLAG_ACTIVITY_NEW_TASK ,其他launchMode启动模式taskAffinity属性无效 

  • launchMode      standard      进入启动task,每次都创建新的实例进入task顶部

                            singleTop    进入启动task,如果已有实例并且在task顶部不创建新实例,调用原实例的onNewIntent(),其它情况都创建新的实例进入task顶部

    •                singleTask   进入指定taskAffinity的task,如果指定的task存在,将task移到前台,如果指定task不存在,创建指定taskAffinity的task
    •                                    如果task中存在实例,则移除实例之上的所有实例并显示出来,执行原实例的onNewIntent(),其它情况则创建实例进入task顶部
    •               singleInstance   进入新的task,并且此task内只存在此一个activity ,不再加入别的activity
    •                                          如果task中存在实例,执行实例的onNewIntent()                  
  • taskAffinity起作用时:       进入指定taskAffinity的task,如果指定的task存在,将task移到前台,如果指定task不存在,创建指定taskAffinity的task 

                                

 

 

而在Intent当中,flag属性控制activity的启动模式:

     FLAG_ACTIVITY_NEW_TASK    进入指定taskAffinity的task,如果指定的task存在,将task移到前台,如果指定task不存在,创建指定taskAffinity的task                                                          

                                                      每次都创建新的实例进入task顶部

     FLAG_ACTIVITY_SINGLE_TOP   进入启动task 

                                                         如果已有实例并且在task顶部不创建新实例,执行实例的onNewIntent(),其它情况都创建新的实例进入task顶部

 

     FLAG_ACTIVITY_CLEAR_TOP    进入启动task 

                                                         如果task中存在实例,则移除实例之上的所有实例,如果启动的activity启动模式不是standard模式,或者flag有FLAG_ACTIVITY_SINGLE_TOP属性

                                                         那么调用Activity B的onNewIntent()方法否则销毁原有实例创建新实例进入task顶部,其它情况则创建实例进入task顶部

 

 

 

 

对activity的启动模式属性中Intent的flag属性覆盖<activity>元素中属性设置;

 

在<activity>元素中,有以下几个属性是可以使用的:

  • taskAffinity
  • launchMode
  • allowTaskReparenting
  • clearTaskOnLaunch
  • alwaysRetainTaskState
  • finishOnTaskLaunch

 

而在Intent当中,有以下几个flag是比较常用的:

  • FLAG_ACTIVITY_NEW_TASK
  • FLAG_ACTIVITY_CLEAR_TOP
  • FLAG_ACTIVITY_SINGLE_TOP

 

 

处理affinity

 

affinity可以用于指定一个Activity更加愿意依附于哪一个任务,在默认情况下,同一个应用程序中的所有Activity都具有相同的affinity,所以,这些Activity都更加倾向于运行在相同的任务当中。当然了,你也可以去改变每个Activity的affinity值,通过<activity>元素的taskAffinity属性就可以实现了。

 

taskAffinity属性接收一个字符串参数,你可以指定成任意的值(经我测试字符串中至少要包含一个.),但必须不能和应用程序的包名相同,因为系统会使用包名来作为默认的affinity值。

 

affinity主要有以下两种应用场景:

  • 当调用startActivity()方法来启动一个Activity时,默认是将它放入到当前的任务当中。但是,如果在Intent中加入了一个FLAG_ACTIVITY_NEW_TASK flag的话(或者该Activity在manifest文件中声明的启动模式是"singleTask"),系统就会尝试为这个Activity单独创建一个任务。但是规则并不是只有这么简单,系统会去检测要启动的这个Activity的affinity和当前任务的affinity是否相同,如果相同的话就会把它放入到现有任务当中,如果不同则会去创建一个新的任务。而同一个程序中所有Activity的affinity默认都是相同的,这也是前面为什么说,同一个应用程序中即使声明成"singleTask",也不会为这个Activity再去创建一个新的任务了。
  • 当把Activity的allowTaskReparenting属性设置成true时,Activity就拥有了一个转移所在任务的能力。具体点来说,就是一个Activity现在是处于某个任务当中的,但是它与另外一个任务具有相同的affinity值,那么当另外这个任务切换到前台的时候,该Activity就可以转移到现在的这个任务当中。
    那还是举一个形象点的例子吧,比如有一个天气预报程序,它有一个Activity是专门用于显示天气信息的,这个Activity和该天气预报程序的所有其它Activity具体相同的affinity值,并且还将allowTaskReparenting属性设置成true了。这个时候,你自己的应用程序通过Intent去启动了这个用于显示天气信息的Activity,那么此时这个Activity应该是和你的应用程序是在同一个任务当中的。但是当把天气预报程序切换到前台的时候,这个Activity又会被转移到天气预报程序的任务当中,并显示出来,因为它们拥有相同的affinity值,并且将allowTaskReparenting属性设置成了true。

清空返回栈

 

如何用户将任务切换到后台之后过了很长一段时间,系统会将这个任务中除了最底层的那个Activity之外的其它所有Activity全部清除掉。当用户重新回到这个任务的时候,最底层的那个Activity将得到恢复。这个是系统默认的行为,因为既然过了这么长的一段时间,用户很有可能早就忘记了当时正在做什么,那么重新回到这个任务的时候,基本上应该是要去做点新的事情了。

 

当然,既然说是默认的行为,那就说明我们肯定是有办法来改变的,在<activity>元素中设置以下几种属性就可以改变系统这一默认行为:

 

alwaysRetainTaskState

如果将最底层的那个Activity的这个属性设置为true,那么上面所描述的默认行为就将不会发生,任务中所有的Activity即使过了很长一段时间之后仍然会被继续保留。

 

clearTaskOnLaunch

如果将最底层的那个Activity的这个属性设置为true,那么只要用户离开了当前任务,再次返回的时候就会将最底层Activity之上的所有其它Activity全部清除掉。简单来讲,就是一种和alwaysRetainTaskState完全相反的工作模式,它保证每次返回任务的时候都会是一种初始化状态,即使用户仅仅离开了很短的一段时间。

 

finishOnTaskLaunch

这个属性和clearTaskOnLaunch是比较类似的,不过它不是作用于整个任务上的,而是作用于单个Activity上。如果某个Activity将这个属性设置成true,那么用户一旦离开了当前任务,再次返回时这个Activity就会被清除掉。


官方对singleTask的定义

The system creates a new task and instantiates the activity at the root of the new task. However, if an instance of the activity already exists in a separate task, the system routes the intent to the existing instance through a call to its onNewIntent() method, rather than creating a new instance. Only one instance of the activity can exist at a time. Although the activity starts in a new task, the Back button still returns the user to the previous activity.

实际上我们在使用时发现,对于设置了"singleTask"启动模式的Activity,它在启动的时候,会先检测系统中属性值affinity等于它的属性值taskAffinity的task是否存在;如果存在这样的task,它就会在这个task中启动,否则就开启一个新的task。因此,如果我们想要设置了"singleTask"启动模式的Activity在新的task中启动,就要为它设置一个独立的taskAffinity属性值,taskAffinity默认情况下是应用的包名。下面的代码中,应用程序的包名是com.fred.testactivity,我们将BActivity的启动模式设置成singleTask, 同时设置其taskAffinity属性为com.fred.testactivity.BActivity 。当BActivity启动时,会发现多了一个task 。代码如下:

<activity
    android:name=".BActivity"
    android:label="@string/title_activity_b"
    android:launchMode="singleTask"
    android:taskAffinity="com.fred.testactivity.BActivity">
</activity>

Google的提醒

我们可以通过设置launchmode和affinity来管理Task, 但Google给了我们一个提醒 --大多数应用不要改变Activity的启动模式, 原文如下

Caution: Most applications should not interrupt the default behavior for activities and tasks. If you determine that it's necessary for your activity to modify the default behaviors, use caution and be sure to test the usability of the activity during launch and when navigating back to it from other activities and tasks with the Back button. Be sure to test for navigation behaviors that might conflict with the user's expected behavior.


猜你喜欢

转载自blog.csdn.net/weixin_37569048/article/details/80508788