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,并观察打印效果。界面如下所示,为了便于理解,按钮的文字真实的表现为其实际动作。
    task activity
  • 接下来分别对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的从属关系
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值