くま's Tech系Blog

基本的には技術で学んだことを書き留めようと思います。雑談もやるかもね!

AndroidアプリのApplicationクラスについて

今回はAndroidアプリのApplicationクラスについてまとめます。

場合によっては使う必要はないのですが、たまに必要になる場合もあるので知っておいて損はないと思います。

Applicationクラスとは?

Applicationクラスは大まかにはアプリ全体のことと捉えてください。

実際の動きとしては、Androidアプリが起動した時に最初にインスタンス化されるクラスです。

このクラスでは、アプリ全体で用いる設定をこのクラスで行います。 例えば、ローカルDBの初期化やHiltのトリガーなどです。

Applicationクラスを作成する

カスタムのApplicationクラスを作成する場合にはApplicationクラスを継承した状態で作成します。

class CuastomApplication: Application() {

    // デバイス構成が変更されたとき
    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
    }

    // アプリケーションの起動時、アクティビティ、サービス、またはレシーバー オブジェクト (コンテンツ プロバイダーを除く) が作成される前
    override fun onCreate() {
        super.onCreate()
    }

     // システム全体のメモリが不足しているとき
    override fun onLowMemory() {
        super.onLowMemory()
    }

    // 不要なメモリを削除するのに適した時期とOSが判断したとき
    override fun onTrimMemory(level: Int) {
        super.onTrimMemory(level)
    }
}

上記がカスタムのApplicationクラスです。Applicationクラスでoverrideできるメソッドでアプリのタイミングを検知することができます。

また、Applicationクラスは次のようにAndroidManifestでクラス名を設定する必要があります。

<application
        android:name=".CuastomApplication">
</application>

Activityの挙動を検知する

先程のカスタムクラスは正直あまり使い所がないと感じませんでしたか?

Applicationクラスを継承するだけでなく、ActivityLifecycleCallbacksを継承することでActivityでの挙動を検知することができます。

ActivityLifecycleCallbacksはActivityのライフサイクルイベントを受け取るインターフェースです。

class CuastomApplication : Application(), Application.ActivityLifecycleCallbacks {
    // Activityでsuper.onCreate()が呼ばれたとき
    override fun onActivityCreated(p0: Activity, p1: Bundle?) {
    }

    // Activityが開始されたとき
    override fun onActivityStarted(p0: Activity) {
    }

    // Activityでsuper.onResume()が呼ばれたとき
    override fun onActivityResumed(p0: Activity) {
    }

    // Activityでsuper.onPause()が呼ばれたとき
    override fun onActivityPaused(p0: Activity) {
    }

    // Activityでsuper.onStop()が呼ばれたとき
    override fun onActivityStopped(p0: Activity) {
    }

    // Activityでsuper.onSaveInstanceState()が呼ばれたとき
    override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) {
    }

    // Activityでsuper.onDestroy()が呼ばれたとき
    override fun onActivityDestroyed(p0: Activity) {
    }
}

上記がActivityLifecycleCallbacksを継承した場合のコードになります。

上記の他にもAPI29で追加された処理があるので公式ドキュメントを確認してみてください。

ただし、このままではアプリ終了時にonActivityDestroyedだけが呼ばれません。

アプリ終了を検知したい場合にApplicationクラスを使いたい人もいると思います。そこでServiceクラスを使ってアプリ終了を検知するようにします。

Serviceクラスは次のように定義します。(必要な部分のみ抜粋)

class CuastomApplication : Application(), Application.ActivityLifecycleCallbacks {

    override fun onCreate() {
        super.onCreate()

        // サービスを開始する
        startService(Intent(this, DestroyService::class.java))
    }
   
        
    // Activityでsuper.onDestroy()が呼ばれたとき
    override fun onActivityDestroyed(p0: Activity) {
    }

    // Destroy検出用のServiceクラス(onBindをimplementしないとエラーになる)
    class DestroyService: Service() {
        override fun onBind(intent: Intent?): IBinder? {
            return null
        }
    }
}

そして、AndroidManifestでサービスを追加します。

<application
    android:name=".CuastomApplication">

<service
    android:name=".CuastomApplication$DestroyService"
    android:stopWithTask="false" />

</application>

android:stopWithTask="false"を設定することで、アプリをキルしたときにServiceを止めるだけでなく、なんらかの処理を行うようにします。(今回はApplicationクラスでアプリキルを検知するためにfalseを設定します)

ここまで設定するとアプリ終了を検知できると思います。

ProcessLifeCycleOwnerについて

アプリのフォアグラウンドやバックグラウンド、アプリ終了の検知にProcessLifeCycleOwnerでいいのではないかと思った方もいると思います。

結論から言うと、使う際には注意が必要です。

以下は、ProcessLifeCycleOwnerを使ったクラスの一例です。

class CuastomApplication : Application(), LifecycleObserver {
    override fun onCreate() {
        super.onCreate()

        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreateLifecycle() {
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onStartLifecycle() {
        // アプリ開始時 or バックグラウンドからの復帰時
    }
}

ProcessLifeCycleOwnerでforegroundを検知したからといって必ずActivityが表示されているわけではないです。 なので、Activityがない状態でダイアログを表示させようとするとクラッシュすると言う例外的なパターンが発生します。

ActivityLifecycleCallbacksはActivityの生成を監視して、1つ目のActivityがスタートされたタイミングを検知するのでContextがないというのはないはずです。

そして、もう1点注意しないといけないのはルート以外のActivity表示されてたら検知できないです。

これらを踏まえて、個人的にはSeriviceクラスを使って検知したほうが安全だと感じています。

最後に

ここまででアプリのライフサイクルをみていきました。

Applicationクラスは便利だと思います。しかし、Contextが想定外だったり、不必要な共通処理を作ってしまったりと不具合を生み出すもとになりえるので必要最低限の使用にとどめましょう!

参照

guides.codepath.com

developer.android.com

developer.android.com

mt312.com