Activity之taskAffinity任务相关性场景分析

Posted hymKing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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交互,比如抖音、微博、微信、淘宝等,来体验使用场景。

以上是关于Activity之taskAffinity任务相关性场景分析的主要内容,如果未能解决你的问题,请参考以下文章

任务栈 Activity的启动模式 Intent中的Flag taskAffinity

Activity之taskAffinity属性allowTaskReparenting属性和Android退出整个应用解决方案

浅谈android:taskAffinity属性及问题解决

错误记录Android 应用安全检测漏洞修复 ( StrandHogg 漏洞 | 设置 Activity 组件 android:taskAffinity=““ )

Android关于Task的一些实践之SingleTask, SingleInstance和TaskAffinity

taskAffinity 属性详解