通过昨天的学习,相信大家已经对Android Activity的四种启动模式有了非常清楚的认识,那么,Android Activity 这四种启动模式有什么区别呢?这就是今天本文要给大家讲解的内容!
        1、standard标准模式
        在standard模式也就是默认模式下,不需要配置launchMode。此时的AndroidManifest.xml如代码清单1-1所示。
        代码清单1-1  AndroidManifest.xml
        
        <?xml version="1.0" encoding="utf-8"?>
            <manifest xmlns:android="//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="//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="//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="//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 | 不允许 |