Blog

Android 12で変わったActivityのLifecycleの話

Android 12ではMaterial Youが採用されたり、スクロールのエフェクトが変わったり、スプラッシュ画面がついたりと、UI周りの変更が多く見られました。

その裏で、セキュリティやパフォーマンス等に関する内部的な変更もいくつか存在します。

今回はその中から、ActivityのLifecycleに一部変更があった点について紹介を行い、また開発者が気をつけるべき点について解説します。

戻るボタンでルートのActivityはDestoryされなくなりました

Android 12から、ルートのActivityを表示しているとき、戻るボタンを押してホーム画面に戻ったときの挙動が変わりました (詳細)。

Android 11以前では、ActivityがDestroyされており、再度起動したときは初期化されonCreateから呼ばれていました。

確認のため、以下のようなActivityでログを見てみます。

class LifecycleLogObserver : LifecycleEventObserver {
    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        Log.d(source::class.java.simpleName, event.name)
    }
}

class SampleActivity: AppCompatActivity() {
    init {
        lifecycle.addObserver(LifecycleLogObserver())
    }
}

Activityを起動し、一度戻るボタンで終了した後に再度開いてみます。

// 初回起動
D/SampleActivity: ON_CREATE
D/SampleActivity: ON_START
D/SampleActivity: ON_RESUME
// 戻るボタン
D/SampleActivity: ON_PAUSE
D/SampleActivity: ON_STOP
D/SampleActivity: ON_DESTROY
// 再度起動
D/SampleActivity: ON_CREATE
D/SampleActivity: ON_START
D/SampleActivity: ON_RESUME

ViewModelも破棄され、 savedInstanceState も保持されないためスクロール位置等もリセットされます。

次にAndroid 12の挙動です。onDestory が呼ばれなくなり、再開時も onStart から呼ばれています。

// 初回起動
D/SampleActivity: ON_CREATE
D/SampleActivity: ON_START
D/SampleActivity: ON_RESUME
// 戻るボタン
D/SampleActivity: ON_PAUSE
D/SampleActivity: ON_STOP
// 再度起動
D/SampleActivity: ON_START
D/SampleActivity: ON_RESUME

ViewModelも破棄されていないので、全ての状態はそのまま再開されます。

これは、ホームボタンを押してホームに戻ったときと全く同じLifecycleとなります。

ちなみに、ここでいうルートのActivityとは、 ACTION_MAINCATEGORY_LAUNCHER が指定されているactivityのことで、通知やWidget、deep link等によって起動したルート以外のActivityは引き続き戻るボタンでDestroyされます。

この変更により、ほとんどの場合、ユーザーはスムーズにアプリケーションの使用を再開できます。

開発者が気をつけるべきこと

ほとんどの場合、この変更によって問題になることはないでしょう。

考慮する必要がある点として、onBackPressed をoverrideしており、その中で finish を呼んでいる場合に、android 12でもActivityが終了されてしまいます。

この場合は代わりに super.onBackPressed() を呼ぶことで、他のアプリケーションと同じ挙動に合わせることが出来ます。

class SampleActivity : AppCompatActivity() {
    private var flag = true

    override fun onBackPressed() {
        if (flag) {
            flag = false
            return
        }
-        finish()
+        super.onBackPressed()
    }
}

現在では OnBackPressedCallback を使ったほうが容易に戻るボタンのハンドリングを行えるでしょう。

もう1点意識したほうが良いと思うのは、onStop の状態になるケースが増えるということです。

LifecycleがアクティブでないときにUIの更新や不要な処理を抑制することにより、不要なリソースと電力を消費するのを防ぐことができます。

まとめ

今回紹介した変更はそこまで大きな変更ではありませんが、ユーザにとっては便利に感じるタイミングもあるでしょう。

Lifecycleは複雑で難しいですが、正しく理解することでユーザのリソースを効率よく使うことが出来ます。

開発者はOSの方針を理解し、それに応じた実装をする必要があると考えています。

人気の記事

kotlin coroutinesのFlow, SharedFlow, StateFlowを整理する

Jetpack ComposeとKotlin Coroutinesを連携させる

Layout Composableを使って複雑なレイアウトを組む【Jetpack Compose】

テスト用Dispatcherの使い分け【Kotlin Coroutines】

Flow.combineの内部実装がすごい話

Jetpack ComposeのRippleエフェクトを深堀り、カスタマイズも