Android任务栏新增最近页面
需求
Android应用启动页面需要在AndroidManifest.xml文件进行注册,常用的应用都有一个Activity被定义成LAUNCHER,这时候点击应用图标时就会启动该Activity。在应用界面相互切换时系统维护的Activity栈会执行进出栈操作。这时候切换到后台任务管理界面(最近使用的应用界面)会看到每个应用只显示一个后台任务。
我们开发的项目需要创建多个快捷方式,也就是一个应用需要多个入口,这个需求通过创建多个应用快捷方式不难实现。
但是因通过不同入口进入时处理的业务也不相同,这就需要每个入口进入应用后都在后台任务管理界面独立创建一个新的后台展示界面,且实现同一应用的各个后台界面进入应用内跳转、退出互不影响。这个需求类似于微信应用与各个公众号快捷菜单的关系:通过公众号快捷菜单打开的公众号独立于微信应用,他们互不干涉。
探究
刚看到这个需求时,第一感觉需要自己处理Activity栈,通过不同方式打开的页面使用不同的栈进行维护。但是这样维护成本比较大,且存在较大风险。
中间方案
通过查阅Android官方文档,发现在Android 5.0(API 21)中引入了以文档为中心的模型,也就是说,如果同一 Activity 的多个实例包含不同的文档,它们可能会在最近使用的应用屏幕中显示为任务。通过新增的 API 允许将应用中不同的 Activity 作为单个文档与其他最近使用的应用屏幕一并显示。
实际测试发现,确实可以实现效果。实现代码如下(以sleepassistant项目代码举例):
显式Intent调用方式:
Intent intent = new Intent(mAppCompatActivity, AboutActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
mAppCompatActivity.startActivity(intent);
documentLaunchMode方式:
<activity
android:label="@string/nav_string_about"
android:documentLaunchMode="always"
android:name=".activity.AboutActivity" />
注意:使用以上两种方式时,Activity的启动模式(launchMode)需要使用标准模式(或默认模式)才可生效。
通过该Intent方式启动的Activity会在任务栏显示一个新的最近页面。

但是这样还是存在一个问题,若是使用显式Intent调用方式(方法一),那么会出现的问题是,快捷方式无法实现flags(无法调用addFlags方法)。查看快捷方式代码如下:
<shortcut
android:shortcutId="shortcut_about"
android:enabled="true"
android:icon="@mipmap/icon_shortcut_backup"
android:shortcutShortLabel="@string/shortcutabout_lable">
<intent
android:action="android.intent.action.VIEW"
android:targetPackage="com.devdroid.sleepassistant"
android:targetClass="com.devdroid.sleepassistant.activity.AboutActivity">
</intent>
</shortcut>
此时 <intent/>下可包含的参数为:
<declare-styleable name="Intent">
<attr name="action" format="string" />
<attr name="data" format="string" />
<attr name="mimeType" />
<attr name="targetPackage" />
<attr name="targetClass" format="string" />
</declare-styleable>
发现没有配置Flags的方式。
若是使用documentLaunchMode方式(方法二),那么会出现的问题是,每次使用该Activity,都会创建一个新的后台任务(我希望根据需求,需要时创建)。
好像又陷入了死胡同。。
最终方案
忽然灵机一动,想到一个非常规的方法。
是不是可以通过快捷菜单使用标准启动方式启动一个中间界面(SkipActivity),在中间界面中再使用显式Intent调用方式(方法一)打开对应的页面(创建后台任务)?
验证代码如下:
快捷菜单代码:
<shortcut
android:shortcutId="shortcut_about"
android:enabled="true"
android:icon="@mipmap/icon_shortcut_backup"
android:shortcutShortLabel="@string/shortcutabout_lable">
<intent
android:action="android.intent.action.VIEW"
android:targetPackage="com.devdroid.sleepassistant"
android:targetClass="com.devdroid.sleepassistant.activity.SkipActivity">
<extra
android:name="action"
android:value="about"/>
</intent>
</shortcut>
SkipActivity主要代码:
@Override
protected void onResume() {
super.onResume();
Intent intent = getIntent();
if(intent != null){
String action = intent.getStringExtra("action");
if("about".equals(action)) {
Intent inten = new Intent(this, AboutActivity.class) ;
inten.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
startActivity(inten);
}
}
}
测试发现确实达到了想要的效果。

总结
- 很多需求设计的技术在Android新版本中可能已经实现,需要经常查阅Android原始文档,跟进学习。
- 作为研发人员,个人感觉该方法是一个取巧的方案,不是官方建议用法、也不是最优方式,仅作为参考。
若是您有更好的实现方式,请告知博主,共同进步。项目相关代码请访问sleepassistant项目获取,或联系本人获取。