Android TaskAffinity和allowTaskReparenting

1.TaskAffinity
affinity是指Activity的归属,Activity与Task的吸附关系,也就是该Activity属于哪个Task。一般情况下在同一个应用中,启动的Activity都在同一个Task中,它们在该Task中度过自己的生命。每个Activity都有taskAffinity属性,这个属性指出了它希望进入的Task。如果一个Activity没有显式的指明taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果Application也没有指明,那么该taskAffinity的值就等于应用的包名。而Task也有自己的affinity属性,它的值等于它的根 Activity的taskAffinity的值。
我们可以通过在元素中增加taskAffinity属性来为某一个Activity指定单独的affinity。这个属性的值是一个字符串,可以指定为任意字符串,但是必须至少包含一个”.”,否则会报错。

2.allowTaskReparenting
翻译过来的意思是允许重新找父母(允许迁移任务栈),该属性用于配置是否允许该activity更换从属的task。
如果一个Activity设置了这个属性,其他应用启动这个activity的时候分两种情况处理:
①这个activity对应的进程已经启动了:则这个activity直接附属到自己所对应的进程的应用栈上
②这个activity对应的进程没有启动:则这个activity先直接附属到启动它的应用的应用栈上,当activity对应的进程启动后,则会主动迁移到activity对应的进程。

也就是说,当下一次将启动 Activity 的任务转至前台时,Activity 是否能从该任务转移至与其有相似性的任务 ,“true”表示可以转移,“false”表示仍须留在启动它的任务处。如果未设置该属性,则对 Activity 应用由 元素的相应 allowTaskReparenting 属性所设置的值。默认值为“false”。
例如,如果电子邮件消息包含网页链接,则点击该链接会调出可显示该网页的 Activity。该 Activity 由浏览器应用定义,但作为电子邮件任务的一部分启动。如果将该 Activity 的父项更改为浏览器任务,则它会在浏览器下一次转至前台时显示,在电子邮件任务再次转至前台时消失。

理解:每个Activty的启动,都会位于一个任务栈中。当将activity的allowTaskReparenting设置为true时,表示当这个Activity被其他应用程序启动后,位于其他应用程序的任务栈中时,启动该应用程序,会将该Activity从其他的任务栈移到本程序的任务栈。

有一个比喻非常之形象:
你捡到一条狗,在家里喂养几天觉得不错,当自己家的了;但是突然有一天他的主人找上门来了,小狗还是乖乖和主人走了。。。
这条狗就是带有allowTaskReparenting属性的activity 。

使用举例:
编写两个应用程序,developArtLearn和taskReparentingTest,在developArtLearn中用隐式意图启动taskReparentingTest的Test这个Activity,该Activity的android:allowTaskReparenting属性设置为true。
taskReparentingTest的主Activity是MainActivity。

public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startActivity(new Intent(“com.android.taskreparentingtest.Test”));
}
}

//Test在清单文件中注册
< activity android:name=".Test"
android:allowTaskReparenting=“true”>
< intent-filter>
< action android:name=“com.android.taskreparentingtest.Test”/>
< category android:name=“android.intent.category.DEFAULT”/>
< /intent-filter>
< /activity>

启动developArtLearn后,用隐式意图启动taskReparentingTest的Test。
在命令行中使用命令 adb shell dumpsys activity 显示模拟器的任务栈情况:
在这里插入图片描述
看到有两个Activity Test和MainActivity,他们都处于同一个任务栈com.android.developartlearn中。当前显示的是Test。
当从桌面点击图标,taskReparentingTest进入应用时,再使用命令adb shell dumpsys activity查看模拟器的任务栈情况:
在这里插入图片描述
可以看到,有两个Activity,他们分处两个不同的任务栈中。可以看到之前的Test(7a63ed9)被移到了新的任务栈com.android.taskreparentingtest任务栈中。

如果去除Test的android:allowTaskReparenting属性,由于android:allowTaskReparenting属性的默认值为false,所以它不会将Test从其他应用程序的任务栈中移到自己应用程序的任务栈中。
启动developArtLearn后,再使用隐式意图启动Test。
在这里插入图片描述
可以看到有两个ActivityTest和MainActivity,他们都处于一个任务栈中com.android.developartlearn。
当从桌面点击图标,taskReparentingTest进入应用时,再使用命令adb shell dumpsys activity查看模拟器的任务栈情况:
在这里插入图片描述
可以看到有三个Activity它们分别处于两个任务栈中,taskReparentingTest的MainActivity,当前正在显示,我们点击应用图标进入该应用的主Activity。它处于com.android.taskreparentingtest任务栈中。
developArtLearn的MainActivity和taskReparentingTest的Test都处于com.android.developartlearn任务栈中。

当将android:allowTaskReparenting置为false时,由developArtLearn用隐式意图启动taskReparentingTest的Test后,再从桌面点击图标进入taskReparentingTest后,它没有将在com.android.developartlearn的Test移到自己的任务栈中,仍然位于之前的任务栈中,而是启动了该应用的主Activity。可以看到它的任务栈com.android.taskreparentingtest中只有MainActivity。

3.TaskAffinity和allowTaskReparenting
一开始,创建的Activity都会在创建它的Task中,并且大部分都在这里度过了它的整个生命。然而有一些情况,创建的Activity会被分配其它的Task中去,有的甚至,本来在一个Task中,之后出现了转移。我们首先分析一下android文档给我们介绍的两种情况。

①第一种情况。如果该Activity的allowTaskReparenting设置为true,它进入后台,当一个和它有相同affinity的Task进入前台时,它会重新宿主,进入到该前台的task中。

验证一下这种情况:
我们创建两个工程,application1和application2,分别含有Activity1和Activity2,它们的taskAffinity相同,均为com.winuxcan.affinity,Activity1的allowTaskReparenting为true,Activity2的allowTaskReparenting为false。
首先,我们启动application1,加载Activity1,然后按Home键,使该task(假设为task1)进入后台。然后启动application2,默认加载Activity2。
我们看到了什么现象?没错,本来应该是显示Activity2,但是却看到了Activity1。实际上Activity2也被加载了,只是Activity1重新宿主,所以看到了Activity1。

②第二种情况。如果加载某个Activity的intent,Flag被设置成FLAG_ACTIVITY_NEW_TASK时,它会首先检查是否存在与自己taskAffinity相同的Task,如果存在,那么它会直接宿主到该Task中,如果不存在则重新创建Task。

我们来做一个测试:
我们首先写一个应用,它有两个Activity(Activity1和Activity2),AndroidManifest.xml如下:
< application android:icon="@drawable/icon" android:label="@string/app_name">
< activity android:name=".Activity1" android:taskAffinity=“com.winuxxan.task”
android:label="@string/app_name">
< /activity>
< activity android:name=".Activity2">
< intent-filter>
< action android:name=“android.intent.action.MAIN” />
< category android:name=“android.intent.category.LAUNCHER” />
< /intent-filter>
< /activity>
< /application>

Activity2的代码如下:
public class Activity2 extends Activity {
private static final String TAG = “Activity2”;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main2);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
Intent intent = new Intent(this, Activity1.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
return super.onTouchEvent(event);
}
}

然后,我们再写一个app应用MyActivity,它包含一个Activity(MyActivity),AndroidManifest.xml如下:
< application android:icon="@drawable/icon" android:label="@string/app_name">
< activity android:name=".MyActivity"
android:taskAffinity=“com.winuxxan.task”
android:label="@string/app_name">
< intent-filter>
< action android:name=“android.intent.action.MAIN”/>
< category android:name=“android.intent.category.LAUNCHER”/>
< /intent-filter>
< /activity>
< /application>

我们首先启动第二个应用MyActivity,然后按Home键,返回到桌面,然后打开Activity2,点击Activity2,进入Activity1。然后按返回键。
我们发现,我们进入Activity的顺序为Activity2->Activity1,而返回时顺序为 Activity1->MyActivity。这就说明了一个问题,Activity1在启动时,重新宿主到了MyActivity所在的Task 中去了。

4.manifest中actvity下的几个配置
①android:allowTaskReparenting:
用来标记Activity能否从启动的Task移动到有着affinity的Task(当这个Task进入到前台时),“true”,表示能移动,“false”,表示它必须呆在启动时呆在的那个Task里。 如果这个特性没有被设定,设定到< application>元素上的allowTaskReparenting特性的值会应用到Activity上。默认值为“false”。
一般来说,当Activity启动后,它就与启动它的Task关联,并且在那里耗尽它的整个生命周期。当当前的Task不再显示时,你可以使用这个特性来强制Activity移动到有着affinity的Task中。
典型用法是:把一个应用程序的Activity移到另一个应用程序的主Task中。
例如,如果 email中包含一个web页的链接,点击它就会启动一个Activity来显示这个页面。这个Activity是由Browser应用程序定义的,但是,现在它作为email Task的一部分。如果它重新宿主到Browser Task里,当Browser下一次进入到前台时,它就能被看见,并且,当email Task再次进入前台时,就看不到它了。
Actvity的affinity是由taskAffinity特性定义的。Task的affinity是通过读取根Activity的affinity决定。因此,根Activity总是位于相同affinity的Task里。由于启动模式为“singleTask”和“singleInstance”的Activity只能位于Task的底部,因此,重新宿主只能限于“standard”和“singleTop”模式。
②android:alwaysRetainTaskState :
用来标记Activity所在的Task的状态是否总是由系统来保持。 “true”,表示总是;“false”,表示在某种情形下允许系统恢复Task到它的初始化状态。默认值是“false”。这个特性只针对Task的根Activity有意义;对其它Activity来说,忽略之。
一般来说,特定的情形如当用户从主画面重新选择这个Task时,系统会对这个Task进行清理(从stack中删除位于根Activity之上的所有Activivity)。典型的情况,当用户有一段时间没有访问这个Task时也会这么做,例如30分钟。 然而,当这个特性设为“true”时,用户总是能回到这个Task的最新状态,无论他们是如何启动的。这非常有用,例如,像Browser应用程序,这里有很多的状态(例如多个打开的Tab),用户不想丢失这些状态。
③android:clearTaskOnLaunch :
用来标记是否从Task中清除所有的Activity,除了根Activity外(每当从主画面重新启动时)“true”,表示总是清除至它的根Activity,“false”表示不。默认值是“false”。这个特性只对启动一个新的Task的Activity(根Activity)有意义;对Task中其它的Activity忽略。
当这个值为“true”,每次用户重新启动这个Task时,都会进入到它的根Activity中,不管这个Task最后在做些什么,也不管用户是使用BACK还是HOME离开的。当这个值为“false”时,可能会在一些情形下(参考alwaysRetainTaskState特性)清除Task的Activity,但不总是。
假设,某人从主画面启动了Activity P,并从那里迁移至Activity Q。接下来用户按下HOME,然后返回Activity P。一般,用户可能见到的是Activity Q,因为它是P的Task中最后工作的内容。然而,如果P设定这个特性为“true”,当用户按下HOME并使这个Task再次进入前台时,其上的所有的Activity(在这里是Q)都将被清除。因此,当返回到这个Task时,用户只能看到P。
如果这个特性和allowTaskReparenting都设定为“true”,那些能重新宿主的Activity会移动到共享affinity的Task中;剩下的Activity都将被抛弃,如上所述。
④android:finishOnTaskLaunch:
用来标记当用户再次启动它的Task(在主画面选择这个Task)时已经存在的Activity实例是否要关闭(结束)“true”,表示应该关闭,“false”表示不关闭。默认值是“false”。 如果这个特性和allowTaskReparenting都设定为“true”,这个特性胜出。Activity的affinity忽略。这个Activity不会重新宿主,但是会销毁。
⑤android:launchMode:
用于指示Activity如何启动。这里有四种模式,与Intent对象中的Activity Flags(FLAG_ACTIVITY_*变量)共同作用,来决定Activity如何启动来处理Intent。它们是:
“standard”
“singleTop”
“singleTask”
“singleInstance”
默认模式是“standard”。
⑥android:noHistory:
用于标记当用户从Activity上离开并且它在屏幕上不再可见时Activity是否从Activity stack中清除并结束(调用finish()方法)——“true”,表示它应该关闭,“false”,表示不需要。默认值是“false”。“true”值意味着Activity不会留下历史痕迹。因为它不会在Activity stack的Task中保留,因此,用户不能返回它。比如splashActivity界面就可以借用这个。在值为true这种情况下,如果调用了startActivityForResult(),那么相应的回调onActivityResult()则永远回调不到。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值