Activity launchMode之singleTask与taskAffinity扫盲

Activity launchMode之singleTask与taskAffinity扫盲

taskAffinity

  • taskAffinity是用来指示Activity属于哪一个Task的。taskAffinity能够决定以下两件事情(前提是Activity的launchMode为singleTask或者设置了FLAG_ACTIVITY_NEW_TASK):
    1. re-parent
    2. 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的实例对象
    1. 存在:Android系统会直接把Intent路由到那个Task中存在的Activity实例对象上,会通过调用onNewIntent()方法处理,而非创建一个新的Activity实例对象。并且会把在它之上的其它Activity清理掉。
    2. 不存在:创建一个Activity实例对象这是肯定的,但是这里有个容易被忽视的盲点——Android系统首先会检查被调用的Activity的taskAffinity与调用方Task的taskAffinity是否
      一致。如果一致,则新创建的Activity实例对象将会被放在原来的Task之上。否则的话,系统会新建一个Task,然后把新创建的Activity实例对象作为一个根元素放在新Task之上。

理论联系实际

  • 首先创建一个工程,定义三个Activity:FirstActivity、SecondActivity、ThirdActivity。我们将依次打开FirstActivity->SecondActivity->ThirdActivity->SecondActivity,并观察打印效果。界面如下所示,为了便于理解,按钮的文字真实的表现为其实际动作。
    Activity launchMode之singleTask与taskAffinity扫盲_第1张图片
  • 接下来分别对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的从属关系

你可能感兴趣的:(Activity,task,launchMode,singletask,Affinity)