# Android中Activity四种启动模式和taskAffinity属性详解 #(4)

# Android中Activity四种启动模式和taskAffinity属性详解 #(4)原创分享

----------影子侠开发者社区Rong


## 四 实例验证singleInstance的行为 ##

 

根据上面的讲解,并且参考谷歌官方文档,singleInstance的特点可以归结为以下三条:

 

1. 以singleInstance模式启动的Activity具有全局唯一性,即整个系统中只会存在一个这样的实例

 

1. 以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务,被他开启的任何activity都会运行在其他任务中(官方文档上的描述为,singleInstance模式的Activity不允许其他Activity和它共存在一个任务中)

 

1. 被singleInstance模式的Activity开启的其他activity,能够开启一个新任务,但不一定开启新的任务,也可能在已有的一个任务中开启

 

下面对这三个特点分别验证,所使用的示例同样为AndroidTaskTest,只不过会进行一些修改,下面列出它的清单文件:

 

   <?xml version="1.0" encoding="utf-8"?>

         <manifestxmlns:android="http://schemas.android.com/apk/res/android"

            package="com.jg.zhang.androidtasktest"

             android:versionCode="1"

             android:versionName="1.0" >

        

             <uses-sdkandroid:minSdkVersion="10" android:targetSdkVersion="17"/>

        

             <applicationandroid:allowBackup="true"

                android:icon="@drawable/ic_launcher"android:label="androidtasktest">

                

                 <activity android:name="com.jg.zhang.androidtasktest.MainActivity">

                     <intent-filter>

                         <actionandroid:name="android.intent.action.MAIN" />

                         <categoryandroid:name="android.intent.category.LAUNCHER" />

                     </intent-filter>

                 </activity>

                

                  <activityandroid:name="com.jg.zhang.androidtasktest.SecondActivity"

                     android:launchMode="singleInstance">

                      <intent-filter>

                          <actionandroid:name="com.jg.zhang.androidtasktest.ACTION_MY"/>

                          <categoryandroid:name="android.intent.category.DEFAULT"/>

                     </intent-filter>

                  </activity>

                

                  <activityandroid:name="com.jg.zhang.androidtasktest.ThirdActivity"/>

                 

             </application>

            

         </manifest>

 

由上面的清单文件可以知道,该应用包括三个activity,分别为MianActivity,SecondActivity,ThirdActivity,其中SecondActivity启动模式设置为singleInstance。MianActivity可以开启SecondActivity,SecondActivity可以开启ThirdActivity。并且为了可以在其他应用中开启SecondActivity,为SecondActivity设置了一个IntentFilter,这样就可以在其他应用中使用隐式Intent开启SecondActivity。

 

为了更好的验证singleInstance的全局唯一性,还需要其他一个应用,对上面的AndroidTaskTest1进行一些修改即可。AndroidTaskTest1只需要一个MianActivity,在MainActivity中点击按钮会开启AndroidTaskTest应用中的SecondActivity。开启AndroidTaskTest应用中的SecondActivity的代码如下:

 

            

         /**

          * 该方法在布局中按钮的android:onClick属性中指定

          *android:onClick="launchOtherActivity"

          * @param v

          */

         publicvoid launchOtherActivity(View v){

                   Intentintent = new Intent();

                  

                   //以下Action为"com.jg.zhang.androidtasktest.ACTION_MY"

                   //即AndroidTaskTest应用中SecondActivity的action

                   intent.setAction("com.jg.zhang.androidtasktest.ACTION_MY");

                  

                   startActivity(intent);

         }

 

### 下面开始验证第一个特点:以singleInstance模式启动的Activity具有全局唯一性,即整个系统中只会存在一个这样的实例 ###

 

执行如下操作:安装AndroidTaskTest应用,点击MainActivity中的按钮,开启SecondActivity,可以看到如下log输出:

 

![](https://img-blog.csdn.net/20130906210755531?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhbmdqZ19ibG9n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

 

执行adb shell dumpsys activity命令,有以下输出:

 

   TaskRecord{411189e0 #9 A com.jg.zhang.androidtasktest}

                   Run#2: ActivityRecord{4129af80 com.jg.zhang.androidtasktest/.SecondActivity}

                   TaskRecord{41305528#8 A com.jg.zhang.androidtasktest}

                   Run#1: ActivityRecord{41296e60 com.jg.zhang.androidtasktest/.MainActivity}

 

以上可以说明,singleInstance模式的Activity总是会在新的任务中运行(前提是系统中还不存在这样的一个实例) 。

 

下面验证它的全局唯一性,执行以下操作:安装另一个应用AndroidTaskTest1,在开启的MainActivity中点击按钮开启AndroidTaskTest应用中的SecondActivity。看到打印出一条新的日志:

 

![](https://img-blog.csdn.net/20130906212039828?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhbmdqZ19ibG9n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

 

执行adb shell dumpsys activity命令,有以下输出:

 

   TaskRecord{411189e0 #9 A com.jg.zhang.androidtasktest}

                   Run#3: ActivityRecord{4129af80 com.jg.zhang.androidtasktest/.SecondActivity}

         TaskRecord{412dc788#12 A com.jg.zhang.androidtasktest1}

                   Run#2: ActivityRecord{4121c628 com.jg.zhang.androidtasktest1/.MainActivity}

         TaskRecord{41305528#8 A com.jg.zhang.androidtasktest}

                   Run#1: ActivityRecord{41296e60 com.jg.zhang.androidtasktest/.MainActivity}

 

由第一个TaskRecord可以得知,开启的SecondActivity就是上次创建的编号为4129af80的SecondActivity,并且Log中没有再次输出关于SecondActivity的信息,说明SecondActivity并没有重新创建。由此可以得出结论:以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。

 

### 下面开始验证第二个特点:以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务,被他开启的任何activity都会运行在其他任务中 ###

 

重新安装AndroidTaskTest应用,点击MainActivity中的按钮,开启SecondActivity,在SecondActivity中点击按钮,开启ThirdActivity。可以看到有如下Log输出:

 

![](https://img-blog.csdn.net/20130906213932734?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhbmdqZ19ibG9n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

 

执行adb shell dumpsys activity命令,有以下输出:

 

   TaskRecord{412a95b8 #15 A com.jg.zhang.androidtasktest}

                   Run#3: ActivityRecord{411f9318 com.jg.zhang.androidtasktest/.ThirdActivity}

         TaskRecord{41353a68#16 A com.jg.zhang.androidtasktest}

                   Run#2: ActivityRecord{413537c8 com.jg.zhang.androidtasktest/.SecondActivity}

         TaskRecord{412a95b8#15 A com.jg.zhang.androidtasktest}

                   Run#1: ActivityRecord{4123a0c8 com.jg.zhang.androidtasktest/.MainActivity}

 

SecondActivity所在的任务为16,被SecondActivity启动的ThirdActivity所在的任务为15,这就说明以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务,被他开启的任何activity都会运行在其他任务中

 

###下面开始验证第三个特点:被singleInstance模式的Activity开启的其他activity,能够在新的任务中启动,但不一定开启新的任务,也可能在已有的一个任务中开启

 

有上面对第二个特点的验证可以看到,被SecondActivity启动的ThirdActivity并没有运行在一个新开启的任务中,而是和MainActivity运行在了同一个已有的任务中,那么在什么情况下ThirdActivity才会启动一个新的任务呢?

 

现在对程序的清单文件做以下修改,为ThirdActivity增加一个属性taskAffinity:

 

            <activityandroid:name="com.jg.zhang.androidtasktest.ThirdActivity"

             android:taskAffinity="com.jg.zhang.androidtasktest.second"/>

 

重新安装AndroidTaskTest应用,执行和上一步中同样的操作:点击MainActivity中的按钮,开启SecondActivity,在SecondActivity中点击按钮,开启ThirdActivity。可以看到有如下输出:

 

![](https://img-blog.csdn.net/20130906215947562?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhbmdqZ19ibG9n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

 

执行adb shell dumpsys activity命令,有以下输出:

 

   TaskRecord{413551b0 #20 A com.jg.zhang.androidtasktest.second}

                   Run#3: ActivityRecord{412de9c0 com.jg.zhang.androidtasktest/.ThirdActivity}

         TaskRecord{4134b268#19 A com.jg.zhang.androidtasktest}

                   Run#2: ActivityRecord{412a36a0 com.jg.zhang.androidtasktest/.SecondActivity}

         TaskRecord{413131e8#18 A com.jg.zhang.androidtasktest}

                   Run#1: ActivityRecord{41271e10 com.jg.zhang.androidtasktest/.MainActivity}

 

可见,被SecondActivity启动的ThirdActivity启动在了一个新的任务中,即在启动ThirdActivity时创建了一个新任务。这就说明被singleInstance模式的Activity A在开启另一activity B时,能够开启一个新任务,但是是不是真的开启新任务,还要受其他条件的限制,这个条件是:当前系统中是不是已经有了一个activity B的taskAffinity属性指定的任务。

 

其实这种行为和singleTask启动时的情况相同。在Activity的启动模式设置为singleTask时,启动时系统会为它加上FLAG_ACTIVITY_NEW_TASK标志,而被singleInstance模式的Activity开启的activity,启动时系统也会为它加上FLAG_ACTIVITY_NEW_TASK标志,所以他们启动时的情况是相同的,上面再验证singleTask时已经阐述过,现在重新说明一下:

 

由于ThirdActivity是被启动模式为singleInstance类型的Activity(即SecondActivity)启动的,framework会为它它加上FLAG_ACTIVITY_NEW_TASK标志,这时  framework会检索是否已经存在了一个affinity为com.jg.zhang.androidtasktest.second(即ThirdActivity的taskAffinity属性)的任务,

 

如果存在这样的一个任务,则检查在这个任务中是否已经有了一个ThirdActivity的实例,

 

- 如果已经存在一个ThirdActivity的实例,则会重用这个任务和任务中的ThirdActivity实例,将这个任务调到前台,清除位于ThirdActivity上面的所有Activity,显示ThirdActivity,并调用ThirdActivity的onNewIntent()。

- 如果不存在一个ThirdActivity的实例,会在这个任务中创建ThirdActivity的实例,并调用onCreate()方法

 

如果不存在这样的一个任务,会创建一个新的affinity为com.jg.zhang.androidtasktest.second的任务,并且将ThirdActivity启动到这个新的任务中

 

如果ThirdActivity不设置taskAffinity,即ThirdActivity和MainActivity的taskAffinity相同,都为应用的包名,那么ThirdActivity是不会开启一个新任务的,framework中的判定过程如下:

 

1. 在SecondActivity启动ThirdActivity时,因为SecondActivity是singleInstance的,所以设定ThirdActivity的启动标志为FLAG_ACTIVITY_NEW_TASK

 

1. 然后获得ThirdActivity的taskAffinity,即为包名com.jg.zhang.androidtasktest

 

1. 检查是否已经存在一个affinity为com.jg.zhang.androidtasktest的任务,这个任务是存在的,就是MainActivity所在的任务,这个任务是在启动MainActivity时开启的

 

1. 既然已经存在这个任务,就检索在这个任务中是否存在一个ThirdActivity的实例,发现不存在

 

1. 在这个已有的任务中启动一个SecondActivity的实例

 

为了作一个清楚的比较,列出ThirdActivity的taskAffinity属性设为com.jg.zhang.androidtasktest.second时的启动过程

 

1. 在SecondActivity启动ThirdActivity时,因为SecondActivity是singleInstance的,那么设定ThirdActivity的启动标志为FLAG_ACTIVITY_NEW_TASK

 

1. 然后获得ThirdActivity的taskAffinity,即为com.jg.zhang.androidtasktest.second

 

1. 检查是否已经存在一个affinity为com.jg.zhang.androidtasktest.second的任务,这个任务是不存在的

 

1. 创建一个新的affinity为com.jg.zhang.androidtasktest.second的任务,并且将ThirdActivity启动到这个新的任务

 

 

到此singleInstance也介绍完了。

此文章系原创,如需转载,请注明出处影子侠开发者社区www.yingzixia.com

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值