Activity之taskAffinity任務相關性場景分析

TaskAffinity,兩個英文單詞的組合,直譯爲任務相關性,可以用來設置Activity任務棧任務相關性的一個屬性,這個屬性參數指出了Activity所希望進入的任務棧的名稱。

taskAffinity的特性結論

  1. 具有同一相關性的 Activity 歸屬同一任務(從用戶的角度來看,則是歸屬同一“應用”)
  2. 任務的相關性由其根 Activity 的相關性確定。(文中有測試分析)
  3. 我們也可以爲Activity單獨指定TaskAffinity屬性值,來改變一個Activity所需要的任務棧,對一個應用中的Activity進行任務分組。(文中有測試分析)
  4. 如果未設置該屬性,則 Activity 會繼承爲應用設置的任務相關性(請參閱 元素的 taskAffinity 屬性)。應用默認相關性的名稱爲 元素所設置的軟件包名稱。
  5. TaskAffinity屬性一般跟singleTask模式或者跟allowTaskReparenting屬性結合使用,在其它情況下,沒有意義。(重點分析)
  6. 該屬性可以將不同應用中定義的Activity置於同一任務中。
  7. 將該屬性設置爲空字符串,可使指定 Activity 與任何任務均無親和關係。有點像singleInstance的模式。單獨使用一個任務棧,且其內只有指定 Activity的一個實例。

以上的結論條目有點多,但是重點是第5條,在實際使用場景中,我們也是重點分析第5條的結論。

TaskAffinity與singleTask結合使用

下面我們看一下簡單的測試代碼

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hym.launchmode">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".SecondActivity"
            android:taskAffinity="com.hym.taskaffinity"
            android:launchMode="standard" />
        <activity
            android:name=".ThirdActivity"
            android:launchMode="singleTask"
            android:taskAffinity="com.hym.taskaffinity2"/>
        
    </application>

</manifest>

FirstActivity啓動SecondActivity,SecondActivity(launchmode=standard)啓動ThirdActivity(launchmode=singleTask)。這裏面省去了Activity中部分代碼,需要測試的可以自行編寫,比較簡單。那麼,三個Activity都啓動完成後,我們打開控制檯通過敲adb shell dumpsys activity activities回車,我們能看到當前的任務棧信息如下

通過這個實例說明兩點:

1、taskAffinity屬性結合singleTask啓動模式一起使用,會創建一個新的任務棧,給當前的這個Activity。

2、taskAffinity屬性結合stardard啓動模式一起使用,並沒有創建新的任務棧,而是默認存在於啓動這個Activity所在任務棧中。

allowTaskReparenting:

allowTaskReparenting,這個屬性是三個單詞的組合,允許更改父項:允許一個Activity迴歸其原始任務棧。什麼意思呢,其實這個屬性設置後,是允許了一個Activity在特定的情況下,可以進行任務棧切換。

我們仍然做一段測試,應用A中的FirstActivity代碼:

A應用中的FirstActivity.java

package com.hym.launchmode;

import android.content.ComponentName;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               Intent intent=new Intent();
               //打開外部程序設置
               intent.setComponent(new ComponentName("com.hym.laucher2","com.hym.laucher2.ReparentActivity"));
               startActivity(intent);
            }
        });

    }
}

應用2中的ReparentingActivity.java

package com.hym.laucher2;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class ReparentActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_reparent);
    }
}

應用2中的manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hym.laucher2">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!--需要設置允許能被外部引用調用-->
        <activity android:name=".ReparentActivity"
            android:exported="true"
            android:allowTaskReparenting="true"></activity>
    </application>

</manifest>

運行應用1啓動FirstActivity,然後點擊啓動應用2中的ReparentingActivity,然後我們執行shell腳本,adb shelldumpsys activity activities

然後點擊home鍵,回到桌面,然後再點擊應用2的icon後,執行查看腳本

從這兩張截圖,我們分析下,第一張圖,應用2的ReparentingActivity實例,實例的引用編號是269ccc,啓動後,進入到了id=730任務棧中,之後點擊home,回到桌面,點擊應用2的啓動Icon啓動後,我們看到了兩個任務棧,且原ReparentingActivity的實例,進入到了新的任務棧中,任務棧id=731。

此時我們把應用2中的ReparentingActivity配置修改一下android:allowTaskReparenting=“false”,在執行上述的交互操作,然後執行腳本查看任務棧情況:

通過對比我們發現,如果android:allowTaskReparenting="false"的時候,ReparentActivity的實例,並沒有回到應用2啓動後的任務棧中,應用2的任務棧中,只有應用2的laucher:FirstActivity。

從上圖中,第二行的TaskRecord A=com.hym.laucher2,第四行的TaskRecord A=com.hym.lanuchmode。其中“com.hym.laucher2”、“com.hym.lanuchmode”我們可以理解成任務棧的taskAffinity,任務棧的taskAffinity是由這個任務棧中的root activity決定的,比如任務棧“com.hym.lanuchmode”名字是由#0 …FirstActivity的任務棧決定的。

結論是:

  • 對於standard標準模式的如果設置了android:allowTaskReparenting=“true”,在特定的情況下,可以支持Activity的切換。(singleTop同standard的結論)
  • 一個任務棧的root Activity總是擁有和它所在的任務棧具有相同的Activity。
  • 由於以singleTask和singleInstance啓動的Activity只能和任務棧的taskAffinity是一致的,所以屬性allowTaskReparenting在這兩種模式下是無效的。

TaskAffinity和allowTaskReparenting使用場景:

看一下場景:一個e-mail(A應用)應用消息頁面中包含一個網頁鏈接,點擊瀏覽器應用程序c-Activity顯示這個頁面,雖然這個Activity是瀏覽器應用(B應用)定義的,但是activity是由email應用程序調用加載的,所以這個時候該activity屬於e-mail的任務棧task。如果e-mail應用切換到後臺,瀏覽器在下次打開時,如果這個Activity的allowTaskReparenting屬性值是true,此時瀏覽器就會顯示該activity而不顯示瀏覽器主界面,同時,activity也將從e-mail的任務棧遷移到瀏覽器的任務棧,下次打開e-mail時,並不會顯示該Activity。

配合一張簡單的示意圖幫助理解,A應用爲郵件應用,B應用爲瀏覽器應用。

上述場景描述來自於網絡,如果我們在實際開發的過程中,需要達成類似上述場景的交互形式,我們就可以用allowTaskReparenting屬性設置來達成。

終極結論:taskAffinity的使用場景,大多被用於兩個應用之間的頁面交互,在日常的應用開發中,使用並不是很多。有興趣的可以去體驗一些大廠開發的能夠被三方調用的一些app交互,比如抖音、微博、微信、淘寶等,來體驗使用場景。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章