Activity之taskAffinity任务相关性场景分析
Posted hymKing
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Activity之taskAffinity任务相关性场景分析相关的知识,希望对你有一定的参考价值。
TaskAffinity,两个英文单词的组合,直译为任务相关性,可以用来设置Activity任务栈任务相关性的一个属性,这个属性参数指出了Activity所希望进入的任务栈的名称。
taskAffinity的特性结论:
- 具有同一相关性的 Activity 归属同一任务(从用户的角度来看,则是归属同一“应用”)
- 任务的相关性由其根 Activity 的相关性确定。(文中有测试分析)
- 我们也可以为Activity单独指定TaskAffinity属性值,来改变一个Activity所需要的任务栈,对一个应用中的Activity进行任务分组。(文中有测试分析)
- 如果未设置该属性,则 Activity 会继承为应用设置的任务相关性(请参阅 元素的 taskAffinity 属性)。应用默认相关性的名称为 元素所设置的软件包名称。
- TaskAffinity属性一般跟singleTask模式或者跟allowTaskReparenting属性结合使用,在其它情况下,没有意义。(重点分析)
- 该属性可以将不同应用中定义的Activity置于同一任务中。
- 将该属性设置为空字符串,可使指定 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交互,比如抖音、微博、微信、淘宝等,来体验使用场景。
以上是关于Activity之taskAffinity任务相关性场景分析的主要内容,如果未能解决你的问题,请参考以下文章
任务栈 Activity的启动模式 Intent中的Flag taskAffinity
Activity之taskAffinity属性allowTaskReparenting属性和Android退出整个应用解决方案
错误记录Android 应用安全检测漏洞修复 ( StrandHogg 漏洞 | 设置 Activity 组件 android:taskAffinity=““ )