Android优雅的监听APP前台/后台的状态切换

8,215

前言

先梳理下“前台”的概念。当App对用户可见,并且用户可以与App直接进行交互的时候,此时,我们说App处于前台;而当我们按下Home键回到桌面,此时则App处于“后台”,通过点击图标或者多任务再次进入App,App再次进入前台。有些时候,我们需要对App的前后台的状态改变进行监听,来进行一些操作,比如一些服务的重连等等。

进入正题

Application类中存在一个registerActivityLifecycleCallbacks方法,该方法接受一个ActivityLifecycleCallbacks接口,传入一个匿名内部类后是这样:

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

      @Override
      public void onActivityStarted(Activity activity) {

      }

      @Override
      public void onActivityResumed(Activity activity) {

      }

      @Override
      public void onActivityPaused(Activity activity) {

      }

      @Override
      public void onActivityStopped(Activity activity) {

      }

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

      }

      @Override
      public void onActivityDestroyed(Activity activity) {

      }
    });

我们看到了Activity中的各个熟悉方法的回调。也就是我们注册该接口之后App中任何Activity的生命周期回调都可以在这里拿到,当前,前提是不能注释Activity对应生命周期中的super.onxxx()方法。

可能这么多回调会使代码变得混乱,在大多数时候,我们只需要关心其中的一两个方法。写一个适配类如下:

public class ActivityLifecycleCallbacksAdapter implements Application.ActivityLifecycleCallbacks {

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

  }

  @Override
  public void onActivityStarted(Activity activity) {

  }

  @Override
  public void onActivityResumed(Activity activity) {

  }

  @Override
  public void onActivityPaused(Activity activity) {

  }

  @Override
  public void onActivityStopped(Activity activity) {

  }

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

  }

  @Override
  public void onActivityDestroyed(Activity activity) {

  }
}

什么也不干,只是实现它而已,但是这样做了之后,在调用registerActivityLifecycleCallbacks方法时,我们可以传入我们的适配类,然后重写关注的方法即可。

此时,回到我们本文的探讨,我们知道,当我们的App回到后台,所有的Acticity会依次执行->onPause()-> onStop()方法。而当回到前台的时候,所有的Activity会执行onStart() ->onResume()方法。我们在Application引入一个变量,负责保存当前处于‘苏醒’状态的Activity的个数,同时在上面的回调中不断更新这个变量的值,根据他的值推断出前后台的切换。

   // 监听切换到前台
    private int rusumeActivityCount = 0;
    registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacksAdapter(){
      @Override
      public void onActivityStarted(Activity activity) {
        if (rusumeActivityCount++==0){
          // 执行切换到前台的逻辑
        }
      }

      @Override
      public void onActivityStopped(Activity activity) {
        if(--rusumeActivityCount==0){
            // 执行切换到后台的逻辑
        }
      }
    });

rusumeActivityCount初始为0,在onActivityStarted中自增,并且自增之前判断一下自己的值,如果是0,则表示是第一次启动或者重新回到前台;在rusumeActivityCount自减,如果等于0,则表示App即将进入后台。

我们可以写一个工具类方便使用,写法如下:

public class AppStateTracker {

  public static final int STATE_FOREGROUND = 0;

  public static final int STATE_BACKGROUND = 1;

  private static int currentState;

  public static int getCurrentState() {
    return currentState;
  }

  public interface AppStateChangeListener {
    void appTurnIntoForeground();
    void appTurnIntoBackGround();
  }

  public static void track(Application application, final AppStateChangeListener appStateChangeListener){

    application.registerActivityLifecycleCallbacks(new SimpleActivityLifecycleCallbacks(){

      private int resumeActivityCount = 0;

      @Override
      public void onActivityStarted(Activity activity) {
        if (resumeActivityCount==0){
          currentState = STATE_FOREGROUND;
          appStateChangeListener.appTurnIntoForeground();
        }

        resumeActivityCount++;
      }


      @Override
      public void onActivityStopped(Activity activity) {
        resumeActivityCount--;

        if (resumeActivityCount==0){
          currentState = STATE_BACKGROUND;
          appStateChangeListener.appTurnIntoBackGround();
        }

      }
    });
  }

  private static class SimpleActivityLifecycleCallbacks implements Application
    .ActivityLifecycleCallbacks{

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

    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    @Override
    public void onActivityResumed(Activity activity) {

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {

    }

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

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }
  }
}

在Application的onCreate()方法中调用即可:

  AppStateTracker.track(this, new AppStateTracker.AppStateChangeListener() {
      @Override
      public void appTurnIntoForeground() {
        // 处理app到前台的逻辑
      }

      @Override
      public void appTurnIntoBackGround() {
      // app处理到到后台的逻辑
      }
    });

如果其它地方需要监听前后台状态处理一些逻辑,可以利用EventBus之类的组件在AppStateChangeListener的回调中发出对应的事件即可。

结论

经过自测,在不考虑极端情况下,该方式能准确监听前后台切换状态的改变。并且该方式通过在Application中注册接口回调的方式来监听前后台切换。对Activity无侵入,不需要依赖繁琐的系统服务来判断,代码较少,容易理解,算得上是一种优雅的方式了。