解开Android应用程序组件Activity的“singleTask”之谜(5)

最后,就是调用startActivityLocked函数继续进行启动Activity的操作了。后面的操作这里就不跟下去了,有兴趣的读者可以参考两篇文章Android应用程序启动过程源代码分析Android应用程序内部启动Activity过程(startActivity)的源代码分析

到这里,思路就理清了,虽然SubActivity的launchMode被设置为"singleTask"模式,但是它并不像官方文档描述的一样:The system creates a new task and instantiates the activity at the root of the new task,而是在跟它有相同taskAffinity的任务中启动,并且位于这个任务的堆栈顶端,于是,前面那个图中,就会出现一个带着"singleTask"标签的箭头指向一个任务堆栈顶端的Activity Y了。

那么,我们有没有办法让一个"singleTask"的Activity在新的任务中启动呢?答案是肯定的。从上面的代码分析中,只要我们能够进入函数startActivityUncheckedLocked的这个if语句中:

 if (r.resultTo == null && !addingToTask          && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {   // todo: should do better management of integers.           mService.mCurTask++;          if (mService.mCurTask <= 0) {               mService.mCurTask = 1;          }          r.task = new TaskRecord(mService.mCurTask, r.info, intent,                     (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);          if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r                     + " in new task " + r.task);           newTask = true;           if (mMainStack) {                 mService.addRecentTaskLocked(r.task);           }    }  

那么,这个即将要启动的Activity就会在新的任务中启动了。进入这个if语句需要满足三个条件,r.resultTo为null,launchFlags的Intent.FLAG_ACTIVITY_NEW_TASK位为1,并且addingToTask值为false。从上面的分析中可以看到,当即将要启动的Activity的launchMode为"singleTask",并且调用startActivity时不要求返回要启动的Activity的执行结果时,前面两个条件可以满足,要满足第三个条件,只要当前系统不存在affinity属性值等于即将要启动的Activity的taskAffinity属性值的任务就可以了。

我们可以稍微修改一下上面的AndroidManifest.xml配置文件来做一下这个实验:

<?xml version="1.0" encoding="utf-8"?>     <manifest xmlns:android="http://schemas.android.com/apk/res/android"         package="shy.luo.task"         android:versionCode="1"         android:versionName="1.0">         <application android:icon="@drawable/icon" android:label="@string/app_name">             <activity android:name=".MainActivity"                       android:label="@string/app_name"                     android:taskAffinity="shy.luo.task.main.activity">                 <intent-filter>                     <action android:name="android.intent.action.MAIN" />                     <category android:name="android.intent.category.LAUNCHER" />                 </intent-filter>             </activity>             <activity android:name=".SubActivity"                       android:label="@string/sub_activity"                     android:launchMode="singleTask"                     android:taskAffinity="shy.luo.task.sub.activity">                 <intent-filter>                     <action android:name="shy.luo.task.subactivity"/>                     <category android:name="android.intent.category.DEFAULT"/>                 </intent-filter>             </activity>         </application>     </manifest>    

注意,这里我们设置MainActivity的taskAffinity属性值为"shy.luo.task.main.activity",设置SubActivity的taskAffinity属性值为"shy.luo.task.sub.activity"。重新编译一下程序,在模拟器上把这个应用程序再次跑起来,用“adb shell dumpsys activity”命令再来查看一下系统运行的的任务,就会看到:

 

Running activities (most recent first):       TaskRecord{4069c020 #4 A shy.luo.task.sub.activity}         Run #2: HistoryRecord{40725040 shy.luo.task/.SubActivity}       TaskRecord{40695220 #3 A shy.luo.task.main.activity}         Run #1: HistoryRecord{406b26b8 shy.luo.task/.MainActivity}       TaskRecord{40599c90 #2 A com.android.launcher}         Run #0: HistoryRecord{40646628 com.android.launcher/com.android.launcher2.Launcher}  

这里就可以看到,SubActivity和MainActivity就分别运行在不同的任务中了。

至此,我们总结一下,设置了"singleTask"启动模式的Activity的特点:

1. 设置了"singleTask"启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的任务存在;如果存在这样的任务,它就会在这个任务中启动,否则就会在新任务中启动。因此,如果我们想要设置了"singleTask"启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。

2. 如果设置了"singleTask"启动模式的Activity不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity实例,如果存在,就会把位于这个Activity实例上面的Activity全部结束掉,即最终这个Activity实例会位于任务的堆栈顶端中。

看来,要解开Activity的"singleTask"之谜,还是要自力更生啊,不过,如果我们仔细阅读官方文档,在中,有这样的描述:

As shown in the table above, standard is the default mode and is appropriate for most types of activities. SingleTop is also a common and useful launch mode for many types of activities. The other modes — singleTask and singleInstance —are not appropriate for most applications, since they result in an interaction model that is likely to be unfamiliar to users and is very different from most other applications.

Regardless of the launch mode that you choose, make sure to test the usability of the activity during launch and when navigating back to it from other activities and tasks using the BACK key.

这样看,官方文档也没有坑我们呢,它告诫我们:make sure to test the usability of the activity during launch。

linux

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwgxdw.html