allowTaskReparenting使用,TaskAffinity和allowTaskReparenting结合

270 阅读3分钟

笔者在阅读《Android开发艺术探索》时,遇到了TaskAffinity和allowTaskReparenting结合的情况,书上只给了一个使用Demo思路,但未给实际项目代码,让各位读者自行试验,书上思路如下:

当Taskfinity和alow TaskReparenting结合的时候,这种情况比较复杂,会产生特殊的效果。当一个应用A启动了应用B的某个Activity 后,如果这个Activity的allowTaskReparenting属性为true的话,那么当应用B被启动后,此Activity会直接从应用A的任务栈转移到应用B的任务栈中。这还是很抽象,再具体点,比如现在有2个应用A和B,A启动了B的一个ActivityC,然后按Home键回到桌面,然后再单击B的桌面图标,这个时候并不是启动了B的主Activity,而是重新显示了已经被应用A启动的Activity C,或者说,C从A的任务栈转移到了B的任务栈中。可以这么理解,由于A启动了C,这个时候C只能运行在A的任务栈中,但是C属于B应用,正常情况下,它的Takfinity值肯定不可能和A的任务栈相同(因为包名不同)。所以,当B被启动后,B会创建自己的任务栈,这个时候系统发现C原本所想要的任务栈已经被创建了,所以就把C从A的任务栈中转移过来了。这种情况读者可以写个例子测试一下,这里就不做示例了

那么笔者就开始动手试验:

首先

新建两个项目,分为名为TurnToOtherAPPActivity和TurnToOtherAPPActivity2,将TurnToOtherAPPActivity中MainActivity命名修改为OneActivity1并附上代码:

import android.content.ComponentName
import android.content.Intent
import android.os.Build.VERSION_CODES.R
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button

class OneActivity1 : AppCompatActivity() {
    private val mButton by lazy { findViewById<Button>(R.id.button) }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mButton.setOnClickListener {
            Intent("com.example.turntootherappactivity2.TwoActivity2").apply {
                startActivity(this)
            }
        }


    }
}

请注意这里的"com.example.turntootherappactivity2.TwoActivity2",这是另一个项目的包名+Activity名。 布局文件activity_main如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".OneActivity1">
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Turn TO B"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="A1"
        android:layout_gravity="center"
        android:textSize="30sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</LinearLayout>

另一个项目TurnToOtherAPPActivity2

修改MainActivity命名为:TwoActivity1,此Activity部分不做修改,布局activity_main如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".TwoActivity1">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="B1"
        android:textSize="30sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

其后再新建一个Activity->TwoActivity2,Activity部分也不做修改,布局文件activity_main2如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".TwoActivity2">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="B2"
        android:textSize="30sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

重点是将TurnToOtherAPPActivity2中的AndroidManifest.xml修改TwoActivity2的android:exported="true"还有android:allowTaskReparenting="true",添加android:name="com.example.turntootherappactivity2.TwoActivity2",如下所示:

<application
    android:allowBackup="true"
    android:dataExtractionRules="@xml/data_extraction_rules"
    android:fullBackupContent="@xml/backup_rules"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.TurnToOtherAPPActivity2"
    tools:targetApi="31">
    <activity
        android:name=".TwoActivity2"
        android:exported="true"
        android:allowTaskReparenting="true">
        <intent-filter>
            <action android:name="com.example.turntootherappactivity2.TwoActivity2"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
    </activity>
    <activity
        android:name=".TwoActivity1"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

大功告成,接着按照书上思路进行测试即可

另外

笔者在TurnToOtherAPPActivity调用TurnToOtherAPPActivity2的TwoActivity2使用的是隐式调用,如果使用另一种调用方法:

Intent intent = new Intent
intent.setComponent(new ComponentName("要调用程序的包名",“要调用的程序的入口Activity的完成路径”));
startActivity(intent);`

这样调用是实现不了书上思路的

最后

对于allowTaskReparenting的值为"true"和"false"时不同的情况,读者可以自行试验,那么查看项目栈的方法如下:

adb shell dumpsys activity activities > "C:\Users\zd01\Desktop\新建文本文档.txt"

这里的"C:\Users\zd01\Desktop\新建文本文档.txt"是笔者桌面的文件拖动到cmd命令窗口后生成的

end