Activity的启动模式全解standard,singleTop,singleTask,singleInstance
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属性起作用的有两种模式 singleTask,FLAG_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就会被清除掉。