Android新启动模式之singleInstancePerTask
Android新启动模式之singleInstancePerTask
一.singleInstancePerTask介绍
singleInstancePerTask为android12新增的在standard、singleTop、singleTask、singleInstance之后的第五种启动模式。
Android12对于singleInstancePerTask描述如下(sdk中在platforms/android-31/data/res/values/attrs_manifest.xml路径下,源码中在frameworks/base/core/res/res/values/attrs_manifest.xml路径下):
<!-- The activity can only be running as the root activity of the task, the first activitythat created the task, and therefore there will only be one instance of this activityin a task. In constrast to the {@code singleTask} launch mode, this activity can bestarted in multiple instances in different tasks if the{@code FLAG_ACTIVITY_MULTIPLE_TASK } or {@code FLAG_ACTIVITY_NEW_DOCUMENT} is set.-->`<enum name="singleInstancePerTask" value="4" />
翻译为:
Activity只能作为任务栈的根Activity(第一个Activity)运行创建了任务栈,因此此Activity将只有一个实例在任务栈中。在 {@code singleTask} 启动模式的约束下,此活动可以在不同任务栈的多个实例中启动,如果{@code FLAG_ACTIVITY_MULTIPLE_TASK } 或 {@code FLAG_ACTIVITY_NEW_DOCUMENT} 已设置。
从中描述可以了解singleInstancePerTask的作用和singleTask几乎一样,不过singleInstancePerTask不需要为启动的Activity设置一个特殊的taskAffinity才能创建一个新的Task,即相对于默认在新任务栈中启动的singleTask。
二.singleInstancePerTask demo测试
下面做一个测验查看启动activity时任务栈的情况:
使用adb shell dumpsys activity activities | grep com.example.systemapp查看进程的activity任务栈状态。以默认standard启动模式的MainActivity来启动声明singleInstancePerTask启动模式的SingleInstancePerTaskActivity,接着再启动声明standard启动模式StandardActivity。
在MainActivity启动SingleInstancePerTaskActivity的任务栈情况如下:
Task{81c692c #19 type=standard A=10147:com.example.systemapp U=0 visible=true mode=fullscreen translucent=false sz=1}
* ActivityRecord{d0488df u0 com.example.systemapp/.SingleInstancePerTaskActivity t19}
* Task{e1d436a #18 type=standard A=10147:com.example.systemapp U=0 visible=false mode=fullscreen translucent=true sz=1}
* ActivityRecord{35a6661 u0 com.example.systemapp/.MainActivity t18}
其中由于SingleInstancePerTaskActivity为singleInstancePerTask的启动模式,会新建一条新的任务栈,可以看到有两条任务栈。
接下来在MainActivity启动SingleInstancePerTaskActivity后再从SingleInstancePerTaskActivity启动StandardActivity的任务栈情况如下:
Task{81c692c #19 type=standard A=10147:com.example.systemapp U=0 visible=true mode=fullscreen translucent=false sz=2}
* ActivityRecord{455ff31 u0 com.example.systemapp/.StandardActivity t19}
* ActivityRecord{d0488df u0 com.example.systemapp/.SingleInstancePerTaskActivity t19}
* Task{e1d436a #18 type=standard A=10147:com.example.systemapp U=0 visible=false mode=fullscreen translucent=true sz=1}
* ActivityRecord{35a6661 u0 com.example.systemapp/.MainActivity t18}
可以看到还是只有两条任务栈,StandardActivity存在于SingleInstancePerTaskActivity的任务栈中。
接着再从StandardActivity再去启动SingleInstancePerTaskActivity。
Task{81c692c #19 type=standard A=10147:com.example.systemapp U=0 visible=true mode=fullscreen translucent=false sz=1}
* ActivityRecord{d0488df u0 com.example.systemapp/.SingleInstancePerTaskActivity t19}
* Task{e1d436a #18 type=standard A=10147:com.example.systemapp U=0 visible=false mode=fullscreen translucent=true sz=1}
* ActivityRecord{35a6661 u0 com.example.systemapp/.MainActivity t18}
可以看到任务栈还是两条,只不过SingleInstancePerTaskActivity并不会重新创建而是走了onNewIntent,而StandardActivity和SingleInstancePerTaskActivity同为一个任务栈,因此被销毁,这点类似singleTask的作用。
注意需要在Android12的真机或者模拟器上使用此模式,否则默认为standard模式。
三.和Intent.FLAG_ACTIVITY_MULTIPLE_TASK或Intent.FLAG_ACTIVITY_NEW_DOCUMENT搭配使用
和Intent.FLAG_ACTIVITY_MULTIPLE_TASK或Intent.FLAG_ACTIVITY_NEW_DOCUMENT结合使用。SingleInstancePerTaskActivity再启动SingleInstancePerTaskActivity,则会新启动SingleInstancePerTaskActivity并创建一个新任务栈。如果不设置则只走onNewIntent的回调并不会重新onCreate。
Intent intent = new Intent(SingleInstancePerTaskActivity.this, SingleInstancePerTaskActivity.class);intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);//intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);startActivity(intent);
任务栈情况如下:
Task{bf82c4b #29 type=standard A=10147:com.example.systemapp U=0 visible=true mode=fullscreen translucent=false sz=1}
* ActivityRecord{ea24a0e u0 com.example.systemapp/.SingleInstancePerTaskActivity t29}
* Task{68f9c5f #28 type=standard A=10147:com.example.systemapp U=0 visible=false mode=fullscreen translucent=true sz=1}
* ActivityRecord{a528cfe u0 com.example.systemapp/.SingleInstancePerTaskActivity t28}
* Task{ad4567a #27 type=standard A=10147:com.example.systemapp U=0 visible=false mode=fullscreen translucent=true sz=1}
* ActivityRecord{86222ed u0 com.example.systemapp/.MainActivity t27}
四.taskAffinity介绍
taskAffinity是指Activity的任务栈亲和度,即任务归属,代表该Activity属于哪个任务栈。
使用场景:
1.一般根据taskAffinity重新为Activity选择宿主任务栈(与allowTaskReparenting属性配合使用)
2.启动一个Activity过程中Intent使用了FLAG_ACTIVITY_NEW_TASK标记,根据taskAffinity查找或创建一个新的具有对应taskAffinity的任务栈。
注意点:taskAffinity一般与singleTask搭配使用,当启动的Activity使用standard、singleTop属性时,如果只设置一个特殊的taskAffinity,但是启动它的时候不设置FLAG_ACTIVITY_NEW_TASK,是不会创建新任务栈。指定singleInstance模式和singleInstancePerTask加上taskAffinity则为新的任务栈命名。
五.allowTaskReparenting介绍
allowTaskReparenting属性的作用是Activity的迁移。当allowTaskReparenting属性和TaskAffinity配合使用时,Activity可以从一个任务栈迁移到另一个任务栈。
迁移的规则是:从一个与该Activity TaskAffinity属性不同的任务栈中迁移到与它TaskAffinity相同的任务栈中。
举个例子:当一个应用A启动了应用B的某个Activity后,如果这个Activity的allowTaskReparenting属性设置为true,那么当应用B被启动,此Activity会直接从应用A的任务栈转移到应用B的任务栈中。
具体点来说,现在有两个应用A和B,A启动了B的一个Activity C,然后按Home键回到桌面,然后再单击B的桌面图标,这个时候不是启动了B的主Activity,而是重新显示了已经被应用A启动的Activity C。我们也可以理解为,C从A的任务栈转移到了B的任务栈中。
可以这么理解,由于A启动了C,这个时候C只能运行在A的任务栈中,但是C属于B应用,正常情况下,它的TaskAffinity值肯定不可能和A的任务栈相同,所以当B启动后,B会创建自己的任务栈,这个时候系统发现C原本想要的任务栈已经创建了,所以就把C从A的任务栈中转移过来了。
六.singleInstance和singleInstancePerTask区别
singleInstance表示全局只有一个activity实例。这个Activity得到一个唯一的Task,只有它自己在运行;如果它再次以相同的Intent启动,那么该Task将会被移动到前台,并且它的Activity.onNewIntent()方法被调用。如果这个Activity尝试启动一个新Activity,这个新活动将在一个单独的任务栈中启动。而singleInstancePerTask作用和singleTask相当,只不过会为启动的Activity新建任务栈,同时配合Intent.FLAG_ACTIVITY_MULTIPLE_TASK或Intent.FLAG_ACTIVITY_NEW_DOCUMENT,singleInstancePerTask可以同时存在Activity在不同任务栈中。
欢迎关注我的公众号“虎哥LoveDroid”,原创技术文章第一时间推送。