LoginSignup
12
7

More than 1 year has passed since last update.

OnBackPressedDispatcher周りをシーケンス図にまとめる

Last updated at Posted at 2023-07-12

セッションとかであー完全に理解したってなって10分後ぐらいに忘れるのでメモしておきます。
なにか必要なポイントとかが抜けていたり間違っているポイントがあれば教えてください。

ティラミス API Level 33 未満

1行まとめ: ActivityのonBackPressedを受け取ってcallbackに流す

参考コード

 * class FormEntryFragment : Fragment() {
 *   override fun onAttach(context: Context) {
 *     super.onAttach(context)
 *     val callback = object : OnBackPressedCallback(
 *       true // default to enabled
 *     ) {
 *       override fun handleOnBackPressed() {
 *         showAreYouSureDialog()
 *       }
 *     }
 *     requireActivity().onBackPressedDispatcher.addCallback(
 *       this, // LifecycleOwner
 *       callback
 *     )
 *   }
 * }

システムからonBackPressed()が呼ばれる

ComponentActivity
    @Override
    @MainThread
    @CallSuper
    @Deprecated
    public void onBackPressed() {
        mOnBackPressedDispatcher.onBackPressed();
    }

最後のenableになっているcallbackを探して呼び出す
誰にもハンドリングされなかったらOnBackPressedDispatcherに渡されているfallbackOnBackPressed()を呼び出す

OnBackPressedDispatcher
    @MainThread
    fun onBackPressed() {
        val callback = onBackPressedCallbacks.lastOrNull {
            it.isEnabled
        }
        inProgressCallback = null
        if (callback != null) {
            callback.handleOnBackPressed()
            return
        }
        fallbackOnBackPressed?.run()
    }

ティラミス API 33

1行まとめ: OnBackInvokedDispatcherから受け取ってcallbackに流す

ActivityでmOnBackPressedDispatcher.setOnBackInvokedDispatcherで渡す。

ComponentActivity
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        // Restore the Saved State first so that it is available to
        // OnContextAvailableListener instances
        mSavedStateRegistryController.performRestore(savedInstanceState);
        mContextAwareHelper.dispatchOnContextAvailable(this);
        super.onCreate(savedInstanceState);
        ReportFragment.injectIfNeededIn(this);
        if (Build.VERSION.SDK_INT >= 33) {
            mOnBackPressedDispatcher.setOnBackInvokedDispatcher(
                    Api33Impl.getOnBackInvokedDispatcher(this)
            );
        }

OnBackPressedDispatcher
    init {
        if (Build.VERSION.SDK_INT >= 33) {
            onBackInvokedCallback = if (Build.VERSION.SDK_INT >= 34) {
                Api34Impl.createOnBackAnimationCallback(
                    { backEvent -> onBackStarted(backEvent) },
                    { backEvent -> onBackProgressed(backEvent) },
                    { onBackPressed() },
                    { onBackCancelled() }
                )
            } else {
                // こっち
                Api33Impl.createOnBackInvokedCallback { onBackPressed() }
            }
        }
    }

registerCallbackから呼ばれるメソッド

OnBackPressedDispatcher
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    private fun updateBackInvokedCallbackState(shouldBeRegistered: Boolean) {
        val dispatcher = invokedDispatcher
        val onBackInvokedCallback = onBackInvokedCallback
        if (dispatcher != null && onBackInvokedCallback != null) {
            if (shouldBeRegistered && !backInvokedCallbackRegistered) {
                Api33Impl.registerOnBackInvokedCallback(
                    dispatcher,
                    OnBackInvokedDispatcher.PRIORITY_DEFAULT,
                    onBackInvokedCallback
                )
                backInvokedCallbackRegistered = true
            } else if (!shouldBeRegistered && backInvokedCallbackRegistered) {
                Api33Impl.unregisterOnBackInvokedCallback(
                    dispatcher,
                    onBackInvokedCallback
                )
                backInvokedCallbackRegistered = false
            }
        }
    }
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    internal object Api33Impl {
        @DoNotInline
        fun registerOnBackInvokedCallback(
            dispatcher: Any,
            priority: Int,
            callback: Any
        ) {
            val onBackInvokedDispatcher = dispatcher as OnBackInvokedDispatcher
            val onBackInvokedCallback = callback as OnBackInvokedCallback
            onBackInvokedDispatcher.registerOnBackInvokedCallback(priority, onBackInvokedCallback)
        }

        @DoNotInline
        fun unregisterOnBackInvokedCallback(dispatcher: Any, callback: Any) {
            val onBackInvokedDispatcher = dispatcher as OnBackInvokedDispatcher
            val onBackInvokedCallback = callback as OnBackInvokedCallback
            onBackInvokedDispatcher.unregisterOnBackInvokedCallback(onBackInvokedCallback)
        }

        @DoNotInline
        fun createOnBackInvokedCallback(onBackInvoked: () -> Unit): OnBackInvokedCallback {
            return OnBackInvokedCallback { onBackInvoked() }
        }
    }

API 34

1行まとめ: だいたい33と一緒っぽい。 ただ追加でonBackStartedonBackProgressedなどが呼び出されるようになるみたいです。

OnBackPressedDispatcher
    init {
        if (Build.VERSION.SDK_INT >= 33) {
            onBackInvokedCallback = if (Build.VERSION.SDK_INT >= 34) {
                // こっち
                Api34Impl.createOnBackAnimationCallback(
                    { backEvent -> onBackStarted(backEvent) },
                    { backEvent -> onBackProgressed(backEvent) },
                    { onBackPressed() },
                    { onBackCancelled() }
                )
            } else {
                Api33Impl.createOnBackInvokedCallback { onBackPressed() }
            }
        }
    }

    @RequiresApi(34)
    internal object Api34Impl {
        @DoNotInline
        fun createOnBackAnimationCallback(
            onBackStarted: (backEvent: BackEventCompat) -> Unit,
            onBackProgressed: (backEvent: BackEventCompat) -> Unit,
            onBackInvoked: () -> Unit,
            onBackCancelled: () -> Unit
        ): OnBackInvokedCallback {
            return object : OnBackAnimationCallback {
                override fun onBackStarted(backEvent: BackEvent) {
                    onBackStarted(BackEventCompat(backEvent))
                }

                override fun onBackProgressed(backEvent: BackEvent) {
                    onBackProgressed(BackEventCompat(backEvent))
                }

                override fun onBackInvoked() {
                    onBackInvoked()
                }

                override fun onBackCancelled() {
                    onBackCancelled()
                }
            }
        }
    }

started周りもだいたいonBackPressedと同じ仕組みで動くが、引数にBackEventCompatが渡ってくるところが違いそう

    @MainThread
    private fun onBackStarted(backEvent: BackEventCompat) {
        val callback = onBackPressedCallbacks.lastOrNull {
            it.isEnabled
        }
        inProgressCallback = callback
        if (callback != null) {
            callback.handleOnBackStarted(backEvent)
            return
        }
    }

12
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
7