EDIT MODE

モバイルアプリ開発に関することを書いています

AndroidXでのバックキー制御

AndroidX以前

今までバックキーの制御と言えば、例えば以下のように Activity#onBackPressed() でゴニョゴニョしていました。

    override fun onBackPressed() {
        // バックキーイベントでFragmentで何かしたいとき
        val fragment = supportFragmentManager.findFragmentByTag("HogeFragment")
        fragment?.something()

        // スタックに積んだFragmentを1個前に戻したいとき
        if (supportFragmentManager.backStackEntryCount > 0) {
            supportFragmentManager.popBackStack()
        } else {
            super.onBackPressed()
        }

BackStackとかはまだいいですけど、Fragment側の処理をcallしたいときなどはActivityに特定のFragmentの依存が入ってしまって、残念な気持ちになっていました。

AndroidX以降

AndroidXで提供されているActivityには、Version 1.0.0-alpha01で Activity#addOnBackPressedCallback () というメソッドが追加され、 OnBackPressedCallback インターフェース経由でバックキーのイベントを受けられるようになってました。

つまりFragment内にバックキー制御のロジックを閉じ込めることが出来るということです。控えめに言って最高です。

developer.android.com

こんな感じで書くことが出来ました。

...
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
...

class MyFragment : Fragment() {

    private val callback = object : OnBackPressedCallback {
        override fun handleOnBackPressed(): Boolean {
            return if (isHoge) {
                something()
                true
            } else {
                false
            }
        }
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        activity?.addOnBackPressedCallback(callback)
        ...
    }

    override fun onDestroy() {
        super.onDestroy()
        activity?.removeOnBackPressedCallback(callback)
    }

これだけでも嬉しいですが、リファレンスを見るとArchitecture ComponentのLifecycleにも対応していました。

developer.android.com

つまり先程のサンプルコードは、以下のように書けます。

...
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.Fragment
...

class MyFragment : Fragment() {

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        activity?.addOnBackPressedCallback(this, object : OnBackPressedCallback {
            override fun handleOnBackPressed(): Boolean {
                return if (isHoge) {
                    something()
                    true
                } else {
                    false
                }
            }
        })
        ...
    }

これでaddしたcallbackの開放を気にする必要が無くなりました。コード量も減るし、読みやすいです。 (OnBackPressedCallbackはJavaで実装されているのでSAM変換も可能ですし、実際にはさらにコード量は減らせます。)

これを発見したときにAndroidXに移行して良かったなと、心の底から思いました。AndroidX最高です。