taskAffinity
taskAffinity是用来指示Activity属于哪一个Task的。taskAffinity能够决定以下两件事情(前提是Activity的launchMode为singleTask或者设置了FLAG_ACTIVITY_NEW_TASK):
- re-parent
- Activity的宿主Task
默认情况下,在一个app中的所有Activity都有一样的taskAffinity,但是我们可以设置不同的taskAffinity,为这些Activity分Task。甚至可以在不同的app之中,设置相同的taskAffinity,以达到不同app的activity公用同一个Task的目的。
Note:
- Task的所有Activity只有一个taskAffinity
- Task的taskAffinity,是由Task的root activity定义
singleTask
通常来说,如果Activity中设置launchMode的属性为SingleTask,当我们启动该Activity时,Android系统首先会检查在Task中,是否存在这个Activity的实例对象
- 存在:Android系统会直接把Intent路由到那个Task中存在的Activity实例对象上,会通过调用onNewIntent()方法处理,而非创建一个新的Activity实例对象。并且会把在它之上的其它Activity清理掉。
- 不存在:创建一个Activity实例对象这是肯定的,但是这里有个容易被忽视的盲点——Android系统首先会检查被调用的Activity的taskAffinity与调用方Task的taskAffinity是否一致。如果一致,则新创建的Activity实例对象将会被放在原来的Task之上。否则的话,系统会新建一个Task,然后把新创建的Activity实例对象作为一个根元素放在新Task之上。
理论联系实际
首先创建一个工程,定义三个Activity:FirstActivity、SecondActivity、ThirdActivity。我们将依次打开FirstActivity->SecondActivity->ThirdActivity->SecondActivity,并观察打印效果。界面如下所示,为了便于理解,按钮的文字真实的表现为其实际动作。
接下来分别对SecondActivity设置:default行为、singleTask、singleTask & different taskAffinity:
default
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xplee.task.task" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity
android:name=".FirstActivity"
android:label="FirstActivity"
android:theme="@style/AppTheme.NoActionBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SecondActivity"
android:label="@string/title_activity_second"
android:theme="@style/AppTheme.NoActionBar" >
</activity>
<activity
android:name=".ThirdActivity"
android:label="@string/title_activity_third"
android:theme="@style/AppTheme.NoActionBar" >
</activity>
</application>
</manifest>
依次打开FirstActivity->SecondActivity->ThirdActivity->SecondActivity,查看log信息:
11-08 20:38:54.890 13971-13971/com.xplee.task.task I/xplee: ***************分割线****************
11-08 20:38:54.890 13971-13971/com.xplee.task.task I/xplee: task id:22 FirstActivity onCreate
11-08 20:38:58.510 13971-13971/com.xplee.task.task I/xplee: task id:22 SecondActivity onCreate
11-08 20:39:01.190 13971-13971/com.xplee.task.task I/xplee: task id:22 ThirdActivity onCreate
11-08 20:39:28.600 13971-13971/com.xplee.task.task I/xplee: task id:22 SecondActivity onCreate
可以发现,在默认行为下,它们都在同一个task之中,并且每次都创建一个实例对象,放到Task上。
singleTask
设置SecondActivity的launchMode为singleTask
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xplee.task.task">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".FirstActivity"
android:label="FirstActivity"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SecondActivity"
android:label="@string/title_activity_second"
android:launchMode="singleTask"
android:theme="@style/AppTheme.NoActionBar"></activity>
<activity
android:name=".ThirdActivity"
android:label="@string/title_activity_third"
android:theme="@style/AppTheme.NoActionBar"></activity>
</application>
</manifest>
依次打开FirstActivity->SecondActivity->ThirdActivity->SecondActivity,查看log信息:
11-08 20:49:04.920 17645-17645/com.xplee.task.task I/xplee: ***************分割线****************
11-08 20:49:04.920 17645-17645/com.xplee.task.task I/xplee: task id:24 FirstActivity onCreate
11-08 20:49:15.300 17645-17645/com.xplee.task.task I/xplee: task id:24 SecondActivity onCreate
11-08 20:49:17.170 17645-17645/com.xplee.task.task I/xplee: task id:24 ThirdActivity onCreate
11-08 20:49:22.710 17645-17645/com.xplee.task.task I/xplee: task id:24 SecondActivity onNewIntent
11-08 20:49:23.060 17645-17645/com.xplee.task.task I/xplee: task id:24 ThirdActivity onDestroy
从log信息可以发现,其行为基本与default类似,只有在ThirdActivity启动SecondActivity时,行为有差异:SecondActivity会被重用(onNewIntent()被系统调用),并且将原来SecondActivity之上的ThirdActivity清除。这就是我们文中最开头介绍的singleTask的作用。
singleTask & different taskAffinity
设置SecondActivity的launchMode为singleTask,并且设taskAffinity为com.xplee.task.task.SecondActivity,用来区分app默认的taskAffinity
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xplee.task.task">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".FirstActivity"
android:label="FirstActivity"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SecondActivity"
android:label="@string/title_activity_second"
android:launchMode="singleTask"
android:taskAffinity="com.xplee.task.task.SecondActivity"
android:theme="@style/AppTheme.NoActionBar"></activity>
<activity
android:name=".ThirdActivity"
android:label="@string/title_activity_third"
android:theme="@style/AppTheme.NoActionBar"></activity>
</application>
</manifest>
依次打开FirstActivity->SecondActivity->ThirdActivity->SecondActivity,查看log信息:
11-08 20:58:18.300 22445-22445/com.xplee.task.task I/xplee: ***************分割线****************
11-08 20:58:18.310 22445-22445/com.xplee.task.task I/xplee: task id:26 FirstActivity onCreate
11-08 20:58:29.340 22445-22445/com.xplee.task.task I/xplee: task id:27 SecondActivity onCreate
11-08 20:58:30.920 22445-22445/com.xplee.task.task I/xplee: task id:27 ThirdActivity onCreate
11-08 20:58:33.140 22445-22445/com.xplee.task.task I/xplee: task id:27 SecondActivity onNewIntent
11-08 20:58:33.480 22445-22445/com.xplee.task.task I/xplee: task id:27 ThirdActivity onDestroy
可以发现,这一次app有两个不同的Task。这是因SecondActivity被设置了taskAffinity,与app默认的taskAffinity不一样,而系统在启动启动模式为singleTask的SecondActivity时,会先比较taskAffinity。系统发现它们不一致,因此系统创建一个新的Task(与FirstActivity不在同一个Task),并以SecondActivity作为root activity。
最后当ThirdActivity启动SecondActivity时,由于singleTask的关系,SecondActivity会被重用(onNewIntent()被系统调用),并且将原来SecondActivity之上的ThirdActivity清除
总结
singleTask和taskAffinity在Task Stack的处理中,有密切关系,需要协同分析和使用。
singleTask只会决定Activity在一个Task中的行为,并不能决定Activity与Task的从属关系
taskAffinity犹如一个标志,只有它能够决定Activity与Task的从属关系