1、standard标准模式
在standard模式也就是默认模式下,不需要配置launchMode。此时的AndroidManifest.xml如代码清单1-1所示。
代码清单1-1 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="feixun.com.jiang"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Fx_Main"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Activity2" android:label="@string/Ac2"/>
<activity android:name=".Activity3" android:label="@string/Ac3/>
</application>
<uses-sdk android:minSdkVersion="4" />
</manifest>
运行例子,从Fx_Main开始,一直点回到Activity2按钮时,Log信息如图1所示。
图1 Standard启动模式下Log信息
发现每次都创建了Activity2的新实例。standard的加载模式就是这样的,Intent将发送给它新的Activity实例。
现在点击Android设备的回退键,可以看到Log信息按照刚才创建Activity实例的倒序依次出现,类似退栈的操作,而刚才操作跳转按钮的过程是压栈的操作。
2、 singleTop
singleTop和standard模式,都会将Intent发送到新的实例(如果已经有了,singleTask模式和singleInstance模式不发送到新的实例)。不过,singleTop要求如果创建intent时栈顶已经有要创建Activity的实例,则将Intent发送给该实例,而不发送给新的实例。
还是用刚才的示例,只需将Activity2的launchMode改为singleTop,就能看到区别。修改后AndroidManifest.xml中代码如代码清单1-2所示。
代码清单1-2 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="feixun.com.jiang"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Fx_Main"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Activity2" android:label="@string/Ac2"
android:launchMode="singleTop"/ >
<activity android:name=".Activity3" android:label="@string/Ac3/>
</application>
<uses-sdk android:minSdkVersion="4" />
</manifest>
运行Fx_Main,跳转到Activity2---->Actvity2时会发现,单击多少遍按钮,都是相同的Activity2实例,因为该实例在栈顶,所以不会创建新的实例。如果回退,回到Fx_Main,将退出应用,如图2所示。
图2 singleTop模式下“跳转到AC2”的Log信息
singleTop模式,可用来解决栈顶多个重复相同的Activity的问题。
如果是Fx_Main跳转到Activity2,再跳转到Fx_Main,行为就和standard一样了,会在Activity2跳转到Fx_Main时创建Fx_Main的新实例,因为当时的栈顶不是Activity2实例,如图3所示。
图3 singleTop模式下“跳转到AC2”后“跳回到Main”的Log信息
3、singleTask
singleTask模式和后面的singleInstance模式都是只创建一个实例的。
当Intent到来,需要创建singleTask模式Activity时,系统会检查栈里面是否已经有该Activity的实例。如果有直接将Intent发送给它(注意此时原在此Activity栈中上面的Activity将会被关闭)。
把Activity2的启动模式改成singleTask,修改后AndroidManifest.xml中代码如代码清单1-3所示。
代码清单1-3 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="feixun.com.jiang"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Fx_Main"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Activity2" android:label="@string/Ac2"
android:launchMode="singleTask"/ >
<activity android:name=".Activity3" android:label="@string/Ac3/>
</application>
<uses-sdk android:minSdkVersion="4" />
</manifest>
启动Fx_Main,跳转到Activity2---->Activity3---->Actvity2,此时看Log信息,如图4所示。
图4 singleTask启动模式下Log信息
可见从AC3再跳转到AC2时,因为AC2之前在栈中是存在的所以不生成新的AC2实例,而是在栈中找到此AC2,并将在AC2上面的AC3关闭,所以此时栈中只有Fx_Main和AC2,在AC2点返回会直接退到Fx_Main然后退出。
4、singleInstance
在singleInstance模式下,加载该Activity时如果没有实例化,它会在创建新的Task后,实例化入栈,如果已经存在,则直接调用onNewIntent,该Activity的Task中不允许启动其他的Activity,任何从该Activity启动的其他Activity都将被放到其他Task中,先检查是否有在应用的Task,没有的话就创建。
在这里介绍一下Task(任务)的概念。按照字面意思,任务就是自己要实现的一个目的,而在Android中的Task的定义是一系列Activity的集合,即要达到自己最终要到的Actvity,之前所有经历过的Actvity的集合。它可以是同一个应用内部的,也可以是两个不同应用的。Task可以认为是一个栈,可放入多个Activity。比如,启动一个应用,那么 Android就创建了一个Task,然后启动这个应用的入口Activity,就是intent-filter中配置为main和launch的那个。这个Activity是根(Root)Activity,可能会在它的界面调用其他Activity,这些Activity如果按照上面那3个模式,也会在这个栈(Task)中,只是实例化的策略不同而已。
把Activity2的启动模式改成singleInstance,修改后AndroidManifest.xml中代码如代码清单1-4所示。
代码清单1-4 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="feixun.com.jiang"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Fx_Main"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Activity2" android:label="@string/Ac2"
android:launchMode="singleInstance"/ >
<activity android:name=".Activity3" android:label="@string/Ac3/>
</application>
<uses-sdk android:minSdkVersion="4" />
</manifest>
然后进行测试,启动Fx_Main---->Actvity2---->Actvity3然后看一下Log信息,如图5所示。
图5 singleInstance启动模式下Log信息
可以看到Fx_Main以及Activity3的Task ID为9,而Actvity2的Task ID为10,此时在Actvity3单击“返回”按钮会发现先退到Fx_Main,继续返回会回到Actvity2最后退出。从该过程可以看出:如果从其他应用程序调用singleInstance模式的Activity(Fx_Main),从该Activity开启其他Activity(Activity2)时,会创建一个新的Task(Task ID为10的那个),实际上,如果包含该Activity(Activity2)的Task已经运行的话,他会在该运行的Task中重新创建。
经过上述的介绍,用下面的表格来进行一个简单的总结,如表1-1所示。
表1-1 Activity4种启动模式对比
区别 | 是否允许多个实例 | 如何决定所属Task | 是否每次都生成新实例 | 是否允许其他Activity存在于本Task内 |
standard | 可被多次实例化,同一个Task的不同的实例可位于不同的Task中,每个Task也可包含多个实例 | 存放于Start Activity()的 Task。除非设置 FLAG_ACTIVITY _NEW_TASK标记 | 是 | 允许 |
singleTop | 同standard | 同standard | 如果寄存Activity的栈顶为该Activity,则直接用该Activity处理;否则,创建新实例 | 允许 |
singleTask | 不能有多个实例。由于该模式下Activity总是位于栈顶,所以Actvity在同一个设备里最多只有一个实例 | 放入新的Task内,并且位于该Task的根 | 只有在第一次才创建新的实例,其他情况复用该Activity | 允许。如果存放singleTask的栈寄存在Task内,响应一个Intent时,如果singleTask位于栈顶,则处理Intent,否则会丢失Intent,但该Task会处于前台 |
singleInstance | 同singleTask | 同singleTask | 同singleTask | 不允许 |