Android 应用在后台时,跳转 Activity 会自动切换应用至前台

本博客 demo 见:demo。

平常用手机的时候经常碰到这种情况,用首屏广告举个栗子~很多应用都会有首屏广告 activity A,假设此应用是 app C,如果此时要使用别的应用,就会使得 app C 在后台运行。可是当 activity A 的广告结束后自动跳转 activity B 的时候 app C 总是会自动跳出来切换到前台展示,挡住了我们正在使用的应用,体验非常不好。

这是 android 4.4 后修改的新特性。理想的体验应该是如果应用在后台启动 activity B,那 activity B 也应该同样保持在后台。也就是启动的 activity B 应该保持和启动前时应用的前后台状态一致,才不会影响用户的使用。

有 2 种方案:

1. 在当前 activity A 里处理
在跳转 activity B 前判断应用 C 是否在后台,如果应用 C 在后台,那么就不跳转,并标记变量 ifStartSecondActivity = true,等到应用 C 被切换到前台的时候,因为还没有跳转,所以相当于 activity A 重新在前台展示的时候,在 onResume() 里判断变量 ifStartSecondActivity == true 则执行 startActivity() 跳转至 B;如果应用 C 在前台,正常跳转即可。

判断应用是否在前台:

public boolean isAppOnForeground() {
    ActivityManager activityManager = (ActivityManager) getApplicationContext()
            .getSystemService(Context.ACTIVITY_SERVICE);
    String packageName = getApplicationContext().getPackageName();
 
    List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
    if (appProcesses == null)
        return false;
 
    for (RunningAppProcessInfo appProcess : appProcesses) {
        // The name of the process that this object is associated with.
        if (appProcess.processName.equals(packageName)
                && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
            return true;
        }
    }
 
    return false;
}

注:这样当切换应用至前台时,跳转 B 的时候比较生硬突然,体验不是很好,因为这时其实先显示的还是 A,只是会立马跳转 B,会有一瞬间的闪动,衔接不是很好,如果对时间要求不高,可以加一个延时再跳转。

如果不想延时,希望倒计时结束后打开应用 C ,直接展示的是 activity B,可以使用下面的方法 2。

2. 在需要跳转的 activity B 里处理
这里使用到 activity 的 moveTaskToBack(boolean nonRoot) 方法来使应用切至后台。

官方文档:

/**
 * Move the task containing this activity to the back of the activity
 * stack.  The activity's order within the task is unchanged.
 *
 * 将包含此 activity 的 task 移到活动堆栈的后面。该 task 里的 activity 的顺序不会变。
 *
 * @param nonRoot If false then this only works if the activity is the root
 *                of a task; if true it will work for any activity in
 *                a task.
 *
 *                false:这只会在 activity 是 task 的第一个的时候起作用。
 *                true:对 task 里的所有 activity 都起作用。
 *
 * @return If the task was moved (or it was already at the
 *         back) true is returned, else false.
 *         
 *         如果 task 被移动(或者它已经在后台),则返回 true,否则返回 false。
 */
public boolean moveTaskToBack(boolean nonRoot) {
    try {
        return ActivityManagerNative.getDefault().moveActivityTaskToBack(
                mToken, nonRoot);
    } catch (RemoteException e) {
        // Empty
    }
    return false;
}
其中,判断是否是根 task,可以用 isTaskRoot() 来判断。

/**
 * Return whether this activity is the root of a task.  The root is the
 * first activity in a task.
 *
 * @return True if this is the root activity, else false.
 */
public boolean isTaskRoot() {
    try {
        return ActivityManagerNative.getDefault()
                .getTaskForActivity(mToken, true) >= 0;
    } catch (RemoteException e) {
        return false;
    }
}
若翻译有误,请指正(^_^)

在 activity B 里调用 moveTaskToBack 后,应用会被切至后台运行。

编写代码打印 log 测试:

activity A 里有个倒计时,倒计时结束后会调用 startActivity() 启动 activity B,我们在 activity B 的 onCreate() 里添加 moveTaskToBack()。

activity B 的生命周期如下:

(1)应用在前台打开 activity A ,启动倒计时,在倒计时结束前手动将应用切换至后台。

03-29 19:49:59.756 8312-8312/com.app D/moveTaskToBack: onCreate
03-29 19:49:59.843 8312-8312/com.app D/moveTaskToBack: moveTaskToBack
03-29 19:49:59.939 8312-8312/com.app D/moveTaskToBack: onStart
03-29 19:49:59.944 8312-8312/com.app D/moveTaskToBack: onResume
03-29 19:49:59.951 8312-8312/com.app D/moveTaskToBack: onPause
03-29 19:49:59.984 8312-8312/com.app D/moveTaskToBack: onStop
activity A 在后台倒计时结束后会启动 activity B。

可见 activity B 会执行 onPause() 和 onStop() 自动切换至后台,没有 finish 掉。

(2)倒计时结束后手动将应用切换至前台,会直接展示 activity B。

03-29 19:56:27.842 8312-8312/com.app D/moveTaskToBack: onRestart
03-29 19:56:27.850 8312-8312/com.app D/moveTaskToBack: onStart
03-29 19:56:27.852 8312-8312/com.app D/moveTaskToBack: onResume
activity B 不会再执行 onCreate()。

(3)按返回键返回 activity A。

03-29 19:57:34.397 8312-8312/com.app D/moveTaskToBack: onPause
03-29 19:57:44.432 8312-8312/com.app D/moveTaskToBack: onStop
03-29 19:57:44.433 8312-8312/com.app D/moveTaskToBack: onDestroy
注:不过此方法仍然有个问题,当倒计时进行中时打开多任务界面(Recents screen),倒计时结束的跳转,activity B 的 moveTaskToBack() 不仅会将应用切至后台,还会关闭多任务界面。

观察多任务界面打开、关闭时 activity 的生命周期,发现打开多任务界面时,会执行 onPause() - onStop(),关闭多任务界面时,会执行 onRestart() - onStart() - onResume()。我的猜想是多任务界面和 activity A 在同一个任务栈里面,所以一起切换至后台了。

注:这里是判断的应用是否在前台,而不是当前 activity A 是否在前台(参见博客 Start Acitivity in background on Android 4.4 KitKat)。因为如果此时别的 activity 有 dialog 显示,activity A 被部分遮挡会执行 onPause(),导致 activity B 会执行 moveTaskToBack,出现的效果就是 app 闪退到后台了。可以把他的变量 paused 换成 isVisible,放在 onStart() 和 onStop() 进行赋值判断 activity A 是否可见。

参考:Start Acitivity in background on Android 4.4 KitKat

转载:https://blog.csdn.net/u013719138/article/details/79743895

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值