アプリの終了を検出する(onDestroy)

Androidアプリのライフサイクルを管理したい場合は、皆さんApplicationクラスを使っていると思います。

class MainApplication: Application(), Application.ActivityLifecycleCallbacks {

    override fun onCreate() {
        super.onCreate()
        registerActivityLifecycleCallbacks(this)
    }

    override fun onActivityDestroyed(activity: Activity?) {
        // アプリを終了しても呼ばれない
    }
}

ただし、このままではアプリ終了時のonActivityDestroyedだけが呼ばれないんですよね。

調べてみるとServiceクラスを使うと検出できるらしいので試してみると、無事にonActivityDestroyedが呼ばれるようになりました。

私の使っている改良版がこちら。

import android.app.Application
import android.app.Activity
import android.app.Service
import android.content.Intent
import android.os.Bundle
import android.os.IBinder

class MainApplication: Application(), Application.ActivityLifecycleCallbacks {

    // SharedPreferencesなどで使うためのシングルトン
    companion object {
        lateinit var shared: MainApplication
            private set
    }

    init {
        shared = this
    }

    private var startedCount = 0

    var isRunningInForeground = false

    // Life cycle

    override fun onCreate() {
        super.onCreate()
        registerActivityLifecycleCallbacks(this)
        // サービスを開始する
        startService(Intent(baseContext, DestroyingService::class.java))
    }

    override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
    }

    override fun onActivityStarted(activity: Activity?) {
        if (startedCount == 0) {
            isRunningInForeground = true
            onActivityEnteredInForeground(activity)
        }
        startedCount += 1
    }

    override fun onActivityResumed(activity: Activity?) {
    }

    override fun onActivityPaused(activity: Activity?) {
    }

    override fun onActivityStopped(activity: Activity?) {
        startedCount -= 1
        if (startedCount == 0) {
            isRunningInForeground = false
            onActivityEnteredInBackground(activity)
        }
    }

    private fun onActivityEnteredInForeground(activity: Activity?) {
        // アプリがフォアグラウンドになった時
    }

    private fun onActivityEnteredInBackground(activity: Activity?) {
        // アプリがバックグラウンドになった時
    }

    override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {
    }

    override fun onActivityDestroyed(activity: Activity?) {
        // アプリをタスク画面から終了させた時
    }

    // Destroy検出用のServiceクラス
    class DestroyingService: Service() {

        override fun onBind(intent: Intent?): IBinder? {
            return null
        }
    }
}

DestroyingServiceクラスをAndroidManifest.xmlへ登録しておく。

<application
    android:name=".MainApplication"
    android:label="@string/app_name_display"
    android:allowBackup="false"
    android:supportsRtl="true"
    android:networkSecurityConfig="@xml/network_security_config"
    android:icon="@mipmap/ic_launcher"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:theme="@style/AppTheme">

<service
    android:name=".MainApplication$DestroyingService"
    android:stopWithTask="false" />

</application>

これで基本的なタイミングは全て検出できると思います。