栈内可以重复创建多个实例;
谁启动了这种模式的 Activity,新 Activity 就会运行在启动者所在的栈中
顾名思义,当Activity位于栈顶时不会开启新的Activity,会调用onNewIntent方法
只要 Activity 在一个栈中有实例,多次启动此 Activity 都不会创建实例,也是直接调用 onNewIntent()。启动 singleTask 的 Activity 时,系统会先找有没有想要的任务栈,没有就新建个任务栈;有就看栈里有没有实例栈内有实例,就会把该 Activity 调到栈顶,同时 clearTop(之前在它前面的都被清除)
一个Activity占用一个栈
//如果activity在task存在,拿到最顶端不会启动新的activity
intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
//如果activity在task存在,将activity之上的所有activity结束到
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//默认的跳转类型,将activity放到一个新的Task
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//如果Activty已运行到task,再次跳转不会再运行这个activity;
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
如果需要向flag变量中增加某个FLAG,使用"|"运算符
flag |= XXX_FLAG
原因: 如果flag变量没有XXX_FLAG,则 | 完后flag对应的位为1,如果有XXX_FLAG,则 | 完后值不会变对应位还是1.
如果需要判断flag变量中是否包含XXX_FLAG,使用"&"运算符
flag & XXX_FLAG != 0 或者 flag & XXX_FLAG = XXX_FLAG
原因: 如果flag变量里包含XXX_FLAG,则&完后flag变量对应的位为1,因为XXX_FLAG的定义保证了只有一位非0,其他位都为0,所以如果是包含的话&运算后值不为0,值为此XXX_FLAG的值,不包含的话值为0.
如果需要取消flag变量的XXX_FLAG, 使用 “&~”.
flag &= ~XXX_FLAG
原因: 先对XXX_FLAG进行取反 则XXX_FLAG原来非0的那一位变为0,则使用&运算符后flag变量非0的那一位变为0,则意味着flag变量不包含XXX_FLAG
一般而言,换渠道打开app时我们想要的是带有CLEAR_TOP和NEW_TASK的启动,但是外部调用一般只有NEW_TASK,这也就导致我们在换渠道重新打开后有多首页的现象。
下图是我们希望的流程图,其中【扫一扫】是我们的目标软件

/**
* 本方法处理外部渠道跳转引起的问题:
* 1. 进入渠道变更时,只保留首页
* 2. 渠道变更为桌面时,回到栈顶界面
*/
private void intentFlagHandle() {
// 本方法获取跳转过来的包名
String appName = AppUtil.guessCallAppSource();
Logger.d(TAG, " appName = " + appName);
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
// 已有首页,换渠道时
Logger.d(TAG, " === FLAG_ACTIVITY_BROUGHT_TO_FRONT === ");
if (TextUtils.isEmpty(appName)) {
Logger.d(TAG, "=== FLAG_ACTIVITY_BROUGHT_TO_FRONT === appName = " + appName);
return;
}
// 如果是桌面,返回栈顶,不建新的首页
if (appName.equals(PkgUtils.PKG_MIUI_HOME)) {
Logger.d(TAG, "=== FLAG_ACTIVITY_BROUGHT_TO_FRONT === 桌面跳入");
finish();
return;
}
// 如果是跳转渠道变更,则只保留首页,finish 所有除栈顶的 Activity
Logger.d(TAG, "=== FLAG_ACTIVITY_BROUGHT_TO_FRONT === 跳转渠道已变更");
AppManager.INSTANCE.finishOutTop();
} else {
Logger.d(TAG, " === FLAG_ACTIVITY_BROUGHT_TO_FRONT === 未拦截");
}
}
如此一来只要调用方使用了NEW_TASK(避免我们的Activity在别的app栈里)就可以了,进入我们的代码后全由自己处理
当多渠道使用相同action启动目标app时,若目标app已打开二级界面(即非有action的Activity)时会直接打开栈顶界面,现象与从最近任务启动类似。栈顶Activity的intent没有任何信息,对应action的Activity的intent有action和flag信息,但是不会走生命周期。所以建议此处要做下处理,一个渠道一个action,或者自己能接受现象。
有时候 通过后台唤醒的 Activity 在结束任务后,不想让用户看到,这时候,需要自动的将它隐藏
常规的关闭Activity 是 finish() ,但是如果想Activity关闭后不显示在最近任务中,则需要通过 finishAndRemoveTask() 来关闭
在需要隐藏的那个Activity 配置android:excludeFromRecents="true"即可