Activity的属性taskAffinity

参考资料

https://blog.csdn.net/ljz2009y/article/details/26621815(静下心看,是篇不错的文章)
原文有些啰嗦,借用这篇文章中的demo,和大家一起探讨一下taskAffinity,如有问题,请帮忙指正。

前言

关于Activity两个重要参数:
1.

int taskId = getTaskId();

可以获取当前activity所在栈的id
2.

adb shell dumpsys activity

可以看出Android系统中所有activity的栈信息,进程和application信息
以上两点有助于接下来分析activity的栈内信息

关于taskAffinity

我知道Activity有四种常见的启动模式,之前面试的时候却考了一个常见的启动模式相关,但是我完全没接触过的东西,即Activity的属性taskAffinity。百度了一下,不是很难的东西,记录之。

在Android系统中Activity是用back stack来管理的,关于Activity的taskAffinity属性可以理解为是给当前Activity指定了他应该入的task,taskAffinity的值可以理解为task的name。
关于taskAffinity,我总结了如下几个结论,并会使用demo一一验证。
1.如果不指定taskAffinity属性,应用程序的所有Activity都存放于默认task(single instance启动的activity除外,因为single instance启动的activity独占一个task)
2.指定taskAffinity,只有当Activity设置FLAG_ACTIVITY_NEW_TASK才起作用,否则不起作用。(注意:singleInstance和single Task启动的activity默认是设置了FLAG_ACTIVITY_NEW_TASK的FLAG的)

观点证明1:如果不指定taskAffinity属性,应用程序的所有Activity都存放于默认task

demo如下:
建立三个Activity,布局各为一个按钮,点击按钮从1调到2再跳到3
Activity的代码如下:

//activity1
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int taskId = getTaskId();
        Log.d(TAG, "taskId="+taskId);

    }

    public void to2(View view){
        Intent i = new Intent(this,MainActivity2.class);
        startActivity(i);
    }

    //activity2
    private static final String TAG = "MainActivity2";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        int taskId = getTaskId();
        Log.d(TAG, "taskId="+taskId);
    }

    public void to3(View view){
        Intent i = new Intent(this,MainActivity3.class);
        startActivity(i);
    }

    //Activity3
    private static final String TAG = "MainActivity3";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
        int taskId = getTaskId();
        Log.d(TAG, "taskId="+taskId);

    }

布局如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.test.MainActivity$PlaceholderFragment" >

    <Button
        android:onClick="to2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="move to 2" />

RelativeLayout>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.test.MainActivity$PlaceholderFragment" >

    <Button
        android:onClick="to3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="move to 3" />

RelativeLayout>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.test.MainActivity$PlaceholderFragment" >

    <Button
        android:onClick="is3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="is3" />

RelativeLayout>

清单文件如下:

        <activity
            android:name="com.example.test.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>
        <activity
            android:name="com.example.test.MainActivity2"
            android:label="@string/app_name" >
        activity>
        <activity
            android:name="com.example.test.MainActivity3"
            android:label="@string/app_name" >
        activity>

打印Log:

04-05 14:33:11.528  4727  4727 D MainActivity: taskId=11
04-05 14:33:26.540  4727  4727 D MainActivity2: taskId=11
04-05 14:33:27.816  4727  4727 D MainActivity3: taskId=11

adb shell dumpsys activity信息:

    Task id #11
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
      TaskRecord{a9ebb2d #11 A=com.example.test U=0 StackId=1 sz=3}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNC
HER] flg=0x10000000 cmp=com.example.test/.MainActivity }
        Hist #2: ActivityRecord{3cdc8b5 u0 com.example.test/.MainActivity3 t11}
          Intent { cmp=com.example.test/.MainActivity3 }
          ProcessRecord{46b9862 4727:com.example.test/u0a84}
        Hist #1: ActivityRecord{94af6a7 u0 com.example.test/.MainActivity2 t11}
          Intent { cmp=com.example.test/.MainActivity2 }
          ProcessRecord{46b9862 4727:com.example.test/u0a84}
        Hist #0: ActivityRecord{da2cb3b u0 com.example.test/.MainActivity t11}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.L
AUNCHER] flg=0x10000000 cmp=com.example.test/.MainActivity }
          ProcessRecord{46b9862 4727:com.example.test/u0a84}

分析:我们可以看到,没有指定taskAffinity属性时,所有Activity位于task 11,从下到上为Activity1 Activity2 Activity3,但是single instance是不是例外呢?下面就看一下

观点证明2:如果不指定taskAffinity属性,应用程序的所有Activity都存放于默认task,但是single instance启动的activity除外

demo略做修改,将清单文件中的activity2的lunchmode修改一下,改为android:launchMode=”singleInstance”
完整清单如下:

<activity
            android:name="com.example.test.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>
        <activity
            android:launchMode="singleInstance"
            android:name="com.example.test.MainActivity2"
            android:label="@string/app_name" >
        activity>
        <activity
            android:name="com.example.test.MainActivity3"
            android:label="@string/app_name" >
        activity>

打印Log:

04-05 14:51:35.073  5023  5023 D MainActivity: taskId=12
04-05 14:51:48.255  5023  5023 D MainActivity2: taskId=13
04-05 14:51:51.170  5023  5023 D MainActivity3: taskId=12

adb shell dumpsys activity打印stack信息:

    Task id #12
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
      TaskRecord{3ddfd9a #12 A=com.example.test U=0 StackId=1 sz=2}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNC
HER] flg=0x10000000 cmp=com.example.test/.MainActivity }
        Hist #1: ActivityRecord{9926f1e u0 com.example.test/.MainActivity3 t12}
          Intent { flg=0x10400000 cmp=com.example.test/.MainActivity3 }
          ProcessRecord{7e616cb 5023:com.example.test/u0a84}
        Hist #0: ActivityRecord{f79e620 u0 com.example.test/.MainActivity t12}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.L
AUNCHER] flg=0x10000000 cmp=com.example.test/.MainActivity }
          ProcessRecord{7e616cb 5023:com.example.test/u0a84}
    Task id #13
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
      TaskRecord{3ebbea8 #13 A=com.example.test U=0 StackId=1 sz=1}
      Intent { flg=0x10000000 cmp=com.example.test/.MainActivity2 }
        Hist #0: ActivityRecord{c12be17 u0 com.example.test/.MainActivity2 t13}
          Intent { flg=0x10000000 cmp=com.example.test/.MainActivity2 }
          ProcessRecord{7e616cb 5023:com.example.test/u0a84}

    Running activities (most recent first):
      TaskRecord{3ddfd9a #12 A=com.example.test U=0 StackId=1 sz=2}
        Run #2: ActivityRecord{9926f1e u0 com.example.test/.MainActivity3 t12}
      TaskRecord{3ebbea8 #13 A=com.example.test U=0 StackId=1 sz=1}
        Run #1: ActivityRecord{c12be17 u0 com.example.test/.MainActivity2 t13}
      TaskRecord{3ddfd9a #12 A=com.example.test U=0 StackId=1 sz=2}
        Run #0: ActivityRecord{f79e620 u0 com.example.test/.MainActivity t12}

分析:
可以看到1和3的task id相同,而启动模式为single instance的2单独在一个task,另外,1和3在同一个task,3没有另外建一个task也证明了上一点呢。

证明3指定taskAffinity,当且仅当Activity设置FLAG_ACTIVITY_NEW_TASK才起作用,否则不起作用

该证明我们需要从正反两面验证,一方面要指定taskAffinity并设置FLAG_ACTIVITY_NEW_TASK,另一方面要看单独设置taskAffinity属性是否有用(注意android:taskAffinity=”“属性要么指定为空,要么要以.分隔,如果这样赋值 android:taskAffinity=”test”,会报错)
对程序做如下修改
先从正面证明:
修改Activity1启动Activity2的代码 添加flag,修改activity2清单文件添加属性taskAffinity
代码如下:

        Intent i = new Intent(this,MainActivity2.class);
        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(i);

清单:

        <activity
            android:name="com.example.test.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>
        <activity
            android:taskAffinity="chj.test"
            android:name="com.example.test.MainActivity2"
            android:label="@string/app_name" >
        activity>
        <activity
            android:name="com.example.test.MainActivity3"
            android:label="@string/app_name" >
        activity>

log:

04-05 15:30:09.185  6334  6334 D MainActivity: taskId=20
04-05 15:30:13.418  6334  6334 D MainActivity2: taskId=21
04-05 15:30:14.694  6334  6334 D MainActivity3: taskId=21

stack信息:

    Task id #20
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
      TaskRecord{dc6b9db #20 A=com.example.test U=0 StackId=1 sz=1}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNC
HER] flg=0x10000000 cmp=com.example.test/.MainActivity }
        Hist #0: ActivityRecord{ec1e7b4 u0 com.example.test/.MainActivity t20}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.L
AUNCHER] flg=0x10000000 cmp=com.example.test/.MainActivity }
          ProcessRecord{4a00c78 6334:com.example.test/u0a84}

    Running activities (most recent first):
      TaskRecord{1be02ea #21 A=chj.test U=0 StackId=1 sz=2}
        Run #2: ActivityRecord{99c7704 u0 com.example.test/.MainActivity3 t21}
        Run #1: ActivityRecord{492fc5 u0 com.example.test/.MainActivity2 t21}
      TaskRecord{dc6b9db #20 A=com.example.test U=0 StackId=1 sz=1}
        Run #0: ActivityRecord{ec1e7b4 u0 com.example.test/.MainActivity t20}

分析:可以看到,activity入task时,taskId不同了,之后创建的activity3也和activity2在同一task中
从反面证明:
去掉activity1启动activity2的FLAG设置

        Intent i = new Intent(this,MainActivity2.class);
        startActivity(i);

保留Activity2的taskAffinity属性
log:

04-05 15:39:49.541  6538  6538 D MainActivity: taskId=22
04-05 15:39:55.326  6538  6538 D MainActivity2: taskId=22
04-05 15:39:56.197  6538  6538 D MainActivity3: taskId=22

stack信息:

    Task id #22
    mFullscreen=true
    mBounds=null
    mMinWidth=-1
    mMinHeight=-1
    mLastNonFullscreenBounds=null
      TaskRecord{12efe8b #22 A=com.example.test U=0 StackId=1 sz=3}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNC
HER] flg=0x10000000 cmp=com.example.test/.MainActivity }
        Hist #2: ActivityRecord{a7f6590 u0 com.example.test/.MainActivity3 t22}
          Intent { cmp=com.example.test/.MainActivity3 }
          ProcessRecord{d12eb68 6538:com.example.test/u0a84}
        Hist #1: ActivityRecord{81041d5 u0 com.example.test/.MainActivity2 t22}
          Intent { cmp=com.example.test/.MainActivity2 }
          ProcessRecord{d12eb68 6538:com.example.test/u0a84}
        Hist #0: ActivityRecord{d0d795b u0 com.example.test/.MainActivity t22}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.L
AUNCHER] flg=0x10000000 cmp=com.example.test/.MainActivity }
          ProcessRecord{d12eb68 6538:com.example.test/u0a84}

    Running activities (most recent first):
      TaskRecord{12efe8b #22 A=com.example.test U=0 StackId=1 sz=3}
        Run #2: ActivityRecord{a7f6590 u0 com.example.test/.MainActivity3 t22}
        Run #1: ActivityRecord{81041d5 u0 com.example.test/.MainActivity2 t22}
        Run #0: ActivityRecord{d0d795b u0 com.example.test/.MainActivity t22}

分析:可以看到仅仅为Activity指定taskAffinity=”chj.test”属性,Android并不会新建一个name为chj.test的task呢

你可能感兴趣的:(Android)