こんにちは!Sansan 技術本部 Mobile Applicationグループのふるしんです。
本記事は Sansan Advent Calendar 2021 - Adventar 16日目の記事です。
普段は大阪のオフィスでAndroidアプリの開発に従事しています。 play.google.com
Sansanアプリでは「アプリがバックグラウンドにまわったら即時実行したい処理」があり、その実装に苦労したので共有します。
先に結論
「アプリがバックグラウンドにまわった」判定に androidx.lifecycle.ProcessLifecycleOwner
を使うとハマりどころがあるので注意が必要
WHY?
ProcessLifecycleOwnerはアプリのライフサイクルに反応してくれる便利なクラスです。 パっと見これをonStopでobserveすればとバックグラウンド判定が取れそうだなと思って使ってみました。
ただonPause、onStopの動きがちょっと癖があり注意が必要です。
(※本記事執筆時点でのバージョンは2.3.1です)
癖?
public class ProcessLifecycleOwner implements LifecycleOwner { @VisibleForTesting static final long TIMEOUT_MS = 700; //mls void activityPaused() { mResumedCounter--; if (mResumedCounter == 0) { mHandler.postDelayed(mDelayedPauseRunnable, TIMEOUT_MS); } } void activityStopped() { mStartedCounter--; dispatchStopIfNeeded(); } void dispatchStopIfNeeded() { if (mStartedCounter == 0 && mPauseSent) { mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP); mStopSent = true; } } }
ProcessLifecycleOwnerはonPauseとonStopで700ms分delayさせています。 その理由が公式ドキュメントに書かれています。
Lifecycle.Event.ON_PAUSE, Lifecycle.Event.ON_STOP, events will be dispatched with a delay after a last activity passed through them. This delay is long enough to guarantee that ProcessLifecycleOwner won't send any events if activities are destroyed and recreated due to a configuration change.
訳すとこんな感じでしょうか。
onPauseとonStopのときはdelayした後に処理されます。 このdelayはActivityがdestroyされたり何かしらの変更(画面回転)などを考慮するのに充分な時間を確保しています。
なるほどなるほど。
私達が苦労していたのは、アプリをバックグラウンドにまわしてこのdelay(TIMEOUT_MS)の700msが終わる前に再度アプリを開くとonStopに入っていないためうまく処理を走らせることができていないためでした。
結論
- 「アプリがバックグラウンドにまわった」判定にProcessLifecycleOwnerは使わないほうがいい
- もしProcessLifecycleOwnerを使うのであれば700msのdelayも考慮しよう
ちなみに公式ドキュメントにもこのように書かれています。
It is useful for use cases where you would like to react on your app coming to the foreground or going to the background and you don't need a milliseconds accuracy in receiving lifecycle events.
フォアグラウンド・バックグラウンドに移ったことを検知して、ミリ秒くらい厳密な判断がいらないなら便利ですよ
ということだそうです。
以上です。