(4.3.2.24) Android前后台切换监听的再进化

Android框架自身并未提供前后台监听的解决方案,但是在应用诸多使用场景中又的确需要进行前后台判断,譬如客户端需要在用户切到到后台时开启自动签到以及推送。

王俊峰于2016年7月份提出了一份《Android 前台切换监听新的实现》,其中借助一种类似延时任务的方式进行了前后台切换监听的实现,口袋助理现在使用的前后台监听也是在此基础上稳定运行的。

最近在预研手势锁的需求,其中最常见的应用场景就是:在从后台切换到前台时,要弹出手势锁页面进行解锁。现有的前后台监听机制在用户“开启不保留活动”后,就不能正常触发,然而在手势锁该需求中又必须兼容这种情况,否则用户开启了不保留活动就相当于破解了手势锁,因此,催生了对android前后台监听的再次研究。

一、综述

实现方式onStop生命周期中检测代码当前运行在前台的进程不是我们自己的进程通过延时任务的实现通过计数的实现
依据当应用切到后台的时候,运行在前台的进程由我们的app变成了桌面app 或 其他进程内部跳转,onPause后一定会触发OnResume,在onPause中启动延时任务,onResume中取消;一旦没有onResume,就触发任务,意味着进入了后台onStart和onStop的配对出现原则:内部跳转,当我们从activity A到Activity B时,执行的生命周期的执行顺序如下: A.onPause -> B.onCreate -> B.onStart -> B.onResume -> A.onStop
实现原理在Activity的onStop生命周期中执行检测代码,如果发现当前运行在前台的进程不是我们自己的进程,说明应用切到了后台同上在onStop和onResume中进行计数处理,一旦到达临界值则证明为前后台切换操作
优势使用系统api,屏蔽屏幕旋转或不保留活动等额外操作的影响稳定性可靠,解决了部分机型判断processInf.importance不灵敏的问题屏蔽系统api的差异性,稳定可靠
弊端定制化系统的api函数可能有一定的触发时机差异不支持不保留活动(不保留活动开启后,因为activity的destory,主线程的延时任务被取消掉,即便后台了,也不触发监听)不支持屏幕旋转(当我们旋转设备时activity将会重建,onStart方法将被再次调用,这时将会错误的判断为app第二次被打开。所以若是APP支持水平模式,则不能采用这个办法)
注意事项部分手机的前台进程判断有问题开启不保留活动后失效第一次启动也会认为是后台转前台

二、onStop生命周期中检测代码当前运行在前台的进程不是我们自己的进程

当应用切到后台的时候,运行在前台的进程由我们的app变成了桌面app,依据这一点,我们可以实现检测应用前后台切换的功能。在Activity的onStop生命周期中执行检测代码,如果发现当前运行在前台的进程不是我们自己的进程,说明应用切到了后台。

想想为什么要在onStop中检测,而不是onPause?这是由于A启动B时,生命周期的执行顺序如下:A.onPause->B.onCreate->B.onStart->B.onResume->A.onStop,也就是说,在A的onPause方法中,B的生命周期还没有执行,进程没有进入前台,当然是检测不到的。我们把代码移到onPause生命周期中,发现确实没有效果

/用来控制应用前后台切换的逻辑  
  private boolean isCurrentRunningForeground = true;  
  @Override  
  protected void onStart() {  
      super.onStart();  
      if (!isCurrentRunningForeground) {  
          Log.d(TAG, ">>>>>>>>>>>>>>>>>>>切到前台 activity process");  
      }  
  }  

  @Override  
  protected void onStop() {  
      super.onStop();  
      isCurrentRunningForeground = isRunningForeground();  
      if (!isCurrentRunningForeground) {  
          Log.d(TAG,">>>>>>>>>>>>>>>>>>>切到后台 activity process");  
      }  
  }  

  public boolean isRunningForeground() {  
      ActivityManager activityManager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);  
      List appProcessInfos = activityManager.getRunningAppProcesses();  
      // 枚举进程  
      for (ActivityManager.RunningAppProcessInfo appProcessInfo : appProcessInfos) {  
          if (appProcessInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {  
              if (appProcessInfo.processName.equals(this.getApplicationInfo().processName)) {  
                  Log.d(TAG,"EntryActivity isRunningForeGround");  
                  return true;  
              }  
          }  
      }  
      Log.d(TAG, "EntryActivity isRunningBackGround");  
      return false;  
  }

三、onStart和onStop方法中用变量count计数

我们需要先明确一个生命周期规律:

MainActivity跳转到SecondActivity:
11-06 14:59:09.821 16683-16683/sangfor.com.teststaticlife I/MainActivity: onPause()  
11-06 14:59:09.841 16683-16683/sangfor.com.teststaticlife I/SecondActivity: onCreate()  
11-06 14:59:09.851 16683-16683/sangfor.com.teststaticlife I/SecondActivity: onStart()  
11-06 14:59:09.851 16683-16683/sangfor.com.teststaticlife I/SecondActivity: onPostCreate()  
11-06 14:59:09.851 16683-16683/sangfor.com.teststaticlife I/SecondActivity: onResume()  
11-06 14:59:09.851 16683-16683/sangfor.com.teststaticlife I/SecondActivity: onPostResume()  
11-06 14:59:09.861 16683-16683/sangfor.com.teststaticlife I/SecondActivity: onAttachedToWindow()  
11-06 14:59:09.901 16683-16683/sangfor.com.teststaticlife I/SecondActivity: onWindowFocusChanged():true  
11-06 14:59:09.941 16683-16683/sangfor.com.teststaticlife I/MainActivity: onWindowFocusChanged():false  
11-06 14:59:10.311 16683-16683/sangfor.com.teststaticlife I/MainActivity: onStop()

也就是说:当我们从activity A到Activity B时,执行的生命周期的执行顺序如下:
A.onPause -> B.onCreate -> B.onStart -> B.onResume -> A.onStop

因此我们在Activity的onStart和onStop方法中用变量count计数,在onStart中先判断是否等于0再将变量加1,onStop中先减1再判断是否等于0

假设应用有两个Activity,分别为A和B。

情况1,首先启动AA再启动B,然后关掉B:
    A启动后(onStart后),count=1A启动B,先B.onStart 然后A.onStop,count先加1后减1,count为1。
    关掉B,先A.onStart 然后B.onStop,count先加1后减1,count为1

情况2,首先启动A,然后按Home键返回桌面:
    A启动后(onStart后),count=1;
    按Home键返回桌面,会执行A.onStop,count的计数变位0

关键代码

public class BaseTaskSwitch implements Application.ActivityLifecycleCallbacks {

    public int mCount = 0;
    private OnTaskSwitchListener mOnTaskSwitchListener;
    private static BaseTaskSwitch mBaseLifecycle;

    public static BaseTaskSwitch init(Application application) {
        if (null == mBaseLifecycle) {
            mBaseLifecycle = new BaseTaskSwitch();
            application.registerActivityLifecycleCallbacks(mBaseLifecycle);
        }
        return mBaseLifecycle;
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}

    @Override
    public void onActivityStarted(Activity activity) {
        if (mCount++ == 0) {
            mOnTaskSwitchListener.onTaskSwitchToForeground();
        }
    }

    @Override
    public void onActivityResumed(Activity activity) {}

    @Override
    public void onActivityPaused(Activity activity) {}

    @Override
    public void onActivityStopped(Activity activity) {
        if (--mCount == 0) {
            mOnTaskSwitchListener.onTaskSwitchToBackground();
        }
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}

    @Override
    public void onActivityDestroyed(Activity activity) {}

    public void setOnTaskSwitchListener(OnTaskSwitchListener listener) {
        mOnTaskSwitchListener = listener;
    }

    public interface OnTaskSwitchListener {

        void onTaskSwitchToForeground();

        void onTaskSwitchToBackground();
    }
}

四、结论

鉴于android机型的不可控性,最终还是选择了《onStart和onStop方法中用变量count计数》方式进行前后台监听的实现,从而实现了更准确的前后台监听策略,规避了开启不保留活动对判断的干扰

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值