前言
在介绍启动模式之前,我们先简单的了解一下Android四大组件之一的Activity组件。在Android系统中启动一个Activity,会以任务栈形式来创建的Activity实例并存储,而任务栈是一种“后进先出”的栈结构。如果我么创建多个同样的Activity,那么同样会系统会创建多个实例,并把它们一一放入任务栈中。这样无形之中造成了资源的一种浪费。因此Android系统引入启动模式来管理Activity创建之后的使用。
Affinity简介
在介绍Activity的启动模式前,我们先了解一下更启动模式相关的Affinity。
什么是Affinity
在某些情况下,Android需要知道一个Activity属于哪个任务(Task),即使它没有被启动到一个具体的任务(Task)里。这是通过任务共用性(Affinities)完成的。任务共用性(Affinities)为这个运行一个或多个Activity的Task提供了一个独特的静态名称,默认的一个活动的任务共用性(Affinity)是实现了该Activity的package名。简单的来说,任务栈是依据Affinity而定的,Affinity就相当于是任务栈的门牌。
默认情况,一个应用程序中的所有Activity都拥有相同的affinity。也可以设定这个特性来重组它们,甚至可以把不同应用程序中定义的Activity放置到相同的任务(Task)中。为了明确Activity宿主特定的任务(Task),设定该特性为空的字符串。
如果这个特性没有设置,Activity将从应用程序的设定那里继承下来(参考元素的taskAffinity特性)。应用程序默认的affinity的名字是元素中设定的package名。
与任务有关的 Intent对象中设置的Flag
这里就简单的介绍几个与启动模式有关的Flag,其他的有兴趣可以移驾《Intent启动Activity设置Flags》了解
Flag | 解释 |
---|---|
FLAG_ACTIVITY_CLEAR_TOP | 如果设置成该标记,启动Activity会先查找栈中是否已经存在该Activity,如果存在则移除该Activity顶部所有Activity并再复用该Activity。 |
FLAG_ACTIVITY_NEW_TASK | 如果设置该标记,Activity将在一个全新的栈中创建,一般通过广播启动Activity要用到,否则会报错。 |
FLAG_ACTIVITY_SINGLE_TOP | 如果设置成这种标记,当栈顶的Activity和要启动的Activity一样时就回复用栈顶的Activity而不创建新的。 |
备注:只要是复用的Activity都会执行onNewIntent()方法,且在onNewIntent()中接收新的Intent,onCreate()和onStart()方法不会被调用
Activity的启动模式
Activity的启动模式主要有四种形式,分别为standard、singleTop、singleTask和singleInstance。根据使用的场景和功能同Activity 选择不同的启动模式,不同启动模式的搭配最大化降低了每次都须要在栈中创建一个新的Activity的压力,降低内存使用。同时在某些业务上也起到了简化的作用。
standard
定义:标准模式(这也是系统的默认模式)。
作用:在standard模式下,每次启动一个Activity(不管该实例是否已经存在)
都会重新创建一个新的实例并存入任务栈中(每个活动的Activity都是在栈顶)。standard模式下Activity的创建及存入栈的模式如下图:
如上图,在启动一个Activity_A,会将Activity_A存入任务栈顶;再启动一个Activity_A,会将Activity_A按照栈的存储模式存入栈顶;同样再启动一个Activity_A,会将Activity_A按照栈的存储模式存入栈顶。依照如上如图每次启动的Activity,都会处于栈顶。
配置:由于系统的默认的Activity启动模式是standard,所以在该模式下,无需进行任何配置,如需配置如下。
1、静态配置,在AndroidManifest清单中配置
<application
...
<activity
...
android:launchMode="standard"
...
/activity>
...
</application>
使用场景:该模式没有特定的场景,可以说是最原始的最基础的方式,任何场景下都可以使用。
注意:在该模式下被创建的是实例的生命周期与正常的Activity的生命周期是一样的。
singleTop
定义:栈顶复用模式
作用:在singleTop模式,要区分同一任务是在栈顶还是栈中。如果要启动的Activity处于栈的顶部,那么此时系统不会创建新的实例,而是复用这个栈顶Activity
;如果启动的Activity不在栈的顶部,那么启动的Activity会被重新创建。创建一个新的Activity入栈顶,同Standard模式一样
。如下图:
配置:
1、静态配置,在AndroidManifest清单中配置
<application
...
<activity
...
android:launchMode="singleTop"
...
/activity>
...
</application>
2、动态配置,通过代码配置
Intent intent = new Intent();
intent.setClass(ActivityA.this, ActivityB.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
注意:启动模式的设置(代码配置(Intent设置)的优先级>AndroidMainifest设置)
使用场景:当应用开启渠道多,短时间内被多应用开启调用同一个Activity,那么通过这种设置可以避免已经创建过的Activity被重复创建。例如:应用同时收到2个以上通知,且点开通知打开的Activity相同,那么每次点开通知就创建一个新的Activity,这样就容易照常资源的浪费,如果采用singleTop模式就只会一直服用栈顶的Activity。
注意:在singleTop模式下,如果要启动的Activity位于栈顶,我们再次启动该Activity,同时它的onNewIntent()方法会被执行,可以通过Intent进行传值,Intent传值只能在onNewIntent方法中操作,且它的onCreate()和onStart()方法不会被调用,其他声明周期方法照常。如果要启动的Activity位于栈中,那么如Standard模式一样所有的生命周期方法照常执行。
singleTask
定义:栈内复用模式,也是一种单实例模式
作用:当任务栈中存在与即将启动的Activity相同的Activity,那么系统不会重新创建这个Activity,而是将任务栈中的Activity置顶(因此会将位于它之上的所有Activity销毁推出栈使它成为栈顶
)。然后复用该Activity。如果任务栈中没有与即将启动的Activity相同的Activity,那么将启动的Activity即将创建的方式同standard模式相同。如下:
配置:
1、静态配置,在AndroidManifest清单中配置
<application
...
<activity
...
android:launchMode="singleTask"
...
/activity>
...
</application>
2、动态配置,通过代码配置
Intent intent = new Intent();
intent.setClass(ActivityA.this, ActivityB.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
注意:启动模式的设置(代码配置(Intent设置)的优先级>AndroidMainifest设置)
使用场景:当应用中只希望某个Activity实例仅仅只有一个的情况下,就可以使用该模式,或对于那些及其耗费系统资源的Activity,我们可以考虑将其设为singleTask模式。例如:用户启动N个Activity,这是需要退出应用,那么需要一个Activity一个Activity的销毁,直至全部销毁。假设栈顶的Activity是singleTask模式,就无需这样的操作,只需启动该Activity,然后再退出。
注意:在singleTask模式下,如果任务栈内有存在即将启动的Activity相同的Activity,那么启动后,同时它的onNewIntent()方法会被执行,可以通过Intent进行传值,Intent传值只能在onNewIntent方法中操作,且它的onCreate()和onStart()方法不会被调用,其他声明周期方法照常。如果即将要启动的Activity在栈中没有,那么如Standard模式一样所有的生命周期方法照常执行。
singleInstance
定义:全局单例模式,这是一种加强的singleTask
作用:singleInstance模式具有singleTask模式所具有的所有特性,在这种模式下启动的Activity会在另一个任务栈(不一定开启新的任务,也可能在已有的一个任务中开启
),具有全局唯一性(在整个系统中是单例的
)。当后续再次启动这个activity时,会复用之前的任务栈而不会重新创建。如下图:
配置:
1、静态配置,在AndroidManifest清单中配置
<application
...
<activity
...
android:launchMode="singleInstance"
...
/activity>
...
</application>
2、动态配置,通过代码配置
Intent intent = new Intent();
intent.setClass(ActivityA.this, ActivityB.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
注意:启动模式的设置(代码配置(Intent设置)的优先级>AndroidMainifest设置)
使用场景:当需要与程序分离的页面,如系统的Launch、锁屏键和闹铃等应用,整个系统中仅有一个!所以在我们的应用中一般不会用到。
注意:1、在singleInstance模式下,如果任务栈内有存在即将启动的Activity相同的Activity,那么启动后,同时它的onNewIntent()方法会被执行,可以通过Intent进行传值,Intent传值只能在onNewIntent方法中操作,且它的onCreate()和onStart()方法不会被调用,其他声明周期方法照常。如果即将要启动的Activity在栈中没有,那么如Standard模式一样所有的生命周期方法照常执行。2、还有在singleInstance模式下的Activity用于中间页面,跳转会有问题,比如;A->B(singleInstance)->C,完全退出后,再次启动,首先打开的是B。主要原因是A和C是一个任务栈,B是单独的一个任务栈,在我们B->C后,前台的任务栈又从B的回到了A和C。所以最后退出的任务栈是B的线程,而如果不是重新启动App。上一次最后关闭的任务栈是B的,所以就出现singleInstance模式下的Activity在中间的问题。
总结
在Android应用开发中,良好的用户体验是非常重要的。而在用户体验中,界面的引导和跳转是值得深入研究的重要内容。Activity的四种启动模式使用的场景都不太一样。主要根据实际情况而定。对于这四种启动模式的了解透彻,对于实际开发中绝对会有巨大的帮助的。