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的栈内信息
我知道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的)
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是不是例外呢?下面就看一下
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也证明了上一点呢。
该证明我们需要从正反两面验证,一方面要指定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呢