61
42

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

アプリのバックグラウンド⇆フォアグラウンドを検知する。ProcessLifecycleOwnerの導入

Last updated at Posted at 2017-12-05

CyberAgent Developers Advent Calendar 2017の5日目です。
今日はAbemaTVで最近導入したProcessLifecycleOwnerについて紹介したいと思います。

ProcessLifecycleOwner

今まで、Androidではアプリケーションのバックグラウンド⇆フォアグラウンド検知をすることが難しいとされていました。Activity自体のバックグラウンド⇆フォアグラウンドはonStart/onResumeやonPause/onStopがあるため可能でしたが、Applicationクラスには、onCreate/onTerminateしかありません。

そこで登場したのが ProcessLifecycleOwner です。

公式サイトはこちら

このProcessLifecycleOwnerを使うことでApplicationプロセスの状態を検知することができます。

導入方法

まずはgradleからLifecycleComponentを取り込みます。

build.gradle
implementation "android.arch.lifecycle:extensions:1.0.0"
kapt "android.arch.lifecycle:compiler:1.0.0"

Applicationクラス

app.kt
class App : Application(), LifecycleObserver {

  override fun onCreate() {
    super.onCreate()
    ProcessLifecycleOwner.get().lifecycle.addObserver(this)
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
  fun onAppCreate() {
    Log.i("process", "onCreate")
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_START)
  fun onAppStart() {
    Log.i("process", "onStart")
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
  fun onAppResume() {
    Log.i("process", "onStart")
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
  fun onAppPause() {
    Log.i("process", "onPause")
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
  fun onAppStop() {
    Log.i("process", "onStop")
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
  fun onAppDestroy() {
    Log.i("process", "onDestroy")
  }

}

これでアプリケーションプロセスの状態を検知することができます。

バックグラウンド⇆フォアグラウンド検知

バックグラウンド->フォアグラウンド、フォアグラウンド->バックグラウンドのタイミングで何かしらの処理をしたい場合、 Lifecycle.Event.ON_STARTLifecycle.Event.ON_STOP で処理を行った方がいいです。

理由は、マルチウインドウやPictureInPicture使用時に Lifecycle.Event.ON_RESUMELifecycle.Event.ON_PAUSE が呼ばれてしまうからです。

Lifecycle.Event.ON_DESTROY / onTerminate()

ON_DESTROY will never be dispatched

公式サイトにあるようにLifecycle.Event.ON_DESTROY は呼ばれません。

onTerminate()も呼ばれません。
onTerminate()やLifecycle.Event.ON_DESTROYが呼ばれるタイミングではプロセスが破棄されているからかもしれません。
実際に試して見ても、onTerminate()とLifecycle.Event.ON_DESTROYは呼ばれていませんでした。

Application.java
    /**
     * This method is for use in emulated process environments.  It will
     * never be called on a production Android device, where processes are
     * removed by simply killing them; no user code (including this callback)
     * is executed when doing so.
     */
    @CallSuper
    public void onTerminate() {
    }

どのように実現しているのか

Processのバックグラウンド⇆フォアグラウンドはどのように判定しているのでしょうか?

実際にProcessLifecycleOwnerの中身を見てみます。
以下では必要な部分だけ抜粋して記載しています。

ProcessLifecycleOwner.java

public class ProcessLifecycleOwner implements LifecycleOwner {

    static final long TIMEOUT_MS = 700; //mls
  private int mResumedCounter = 0;

    ・・・

    private Runnable mDelayedPauseRunnable = new Runnable() {
        @Override
        public void run() {
            dispatchPauseIfNeeded();
            dispatchStopIfNeeded();
        }
    };

    ・・・

  void activityResumed() {
    mResumedCounter++;
    if (mResumedCounter == 1) {
        if (mPauseSent) {
            mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
            mPauseSent = false;
        } else {
            mHandler.removeCallbacks(mDelayedPauseRunnable);
        }
    }
  }

    void activityPaused() {
        mResumedCounter--;
        if (mResumedCounter == 0) {
            mHandler.postDelayed(mDelayedPauseRunnable, TIMEOUT_MS);
        }
    }

    ・・・

}

ProcessLifecycleOwnerは180行の比較的小さなクラスです。
中で何をしているかというとまず、LifecycleOwnerをimplementsしてActivityのLifecycleを観測しています。
あるActivityがonPause()に入った段階で、mDelayedPauseRunnableを0.7秒後に呼び出しています。
0.7秒間の間にどこかのActivityでonResume()が呼び出されると、mDelayedPauseRunnableがremoveされますが、逆に0.7秒間でActivity#onResume()が呼ばれなければ、ProcessLifecycleOwnerはApplicationはonPauseとして検知されます。

つまり、Activity#onPause()が呼ばれて、0.7秒間Activity#onResume()が呼び出されなければ、アプリがフォアグラウンド->バックグラウンドへ移行したと認識されます。

また、ApplicationのLifecycle.Event.ON_PAUSEが呼ばれた状態で、Activity#onResume()が呼ばれると、アプリがバックグラウンド->フォアグラウンドへ移行したと認識されます。

最後に

簡単なサンプルアプリを作りましたので、ぜひ見て見てください。

61
42
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
61
42

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?