在单 Activity 多 Fragment 的场景下处理回退按键一直是一件比较恶心的事情。前段时间看 jetpack 在宣传中有提到利用 OnBackPressedDispatcher
处理回退,于是研究了一下。
给 Fragment
声明2个变量
dispatcher: OnBackPressedDispatcher 复制代码
callback: OnBackPressedCallback 复制代码
分别赋值:
dispatcher = requireActivity().onBackPressedDispatcher callback = object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { // 拦截回退 // do something... } } 复制代码
添加回调:
dispatcher.addCallback(this, callback) 复制代码
手动触发回退:
callback.isEnabled = false dispatcher.onBackPressed() 复制代码
先看 Activity的处理:
public void onBackPressed() { mOnBackPressedDispatcher.onBackPressed(); } 复制代码
dispatcher 是一开始就构造的:
private final OnBackPressedDispatcher mOnBackPressedDispatcher = new OnBackPressedDispatcher(new Runnable() { @Override public void run() { ComponentActivity.super.onBackPressed(); } }); 复制代码
回退的时候走dispatcher
的 onBackPressed
:
Iterator<OnBackPressedCallback> iterator = mOnBackPressedCallbacks.descendingIterator(); while (iterator.hasNext()) { OnBackPressedCallback callback = iterator.next(); if (callback.isEnabled()) { callback.handleOnBackPressed(); return; } } if (mFallbackOnBackPressed != null) { mFallbackOnBackPressed.run(); } 复制代码
这里可以看到会把第一个可以触发的 OnBackPressedCallback
触发。注意这里的iterator是降序拿的,也就是后跳的页面先处理。
如果页面都退出了并且 mFallbackOnBackPressed
不是 null,那么随后在它的 run 方法里面触发 Activity 父类的 onBackPressed
方法。
在 dispatcher
添加 callback 的时候,需要传入 lifecycleOwner
参数:
public void addCallback(@NonNull LifecycleOwner owner, @NonNull OnBackPressedCallback onBackPressedCallback) { onBackPressedCallback.addCancellable( new LifecycleOnBackPressedCancellable(lifecycle, onBackPressedCallback)); } 复制代码
这里给 onBackPressedCallback
添加了取消的回调 LifecycleOnBackPressedCancellable
:
@Override public void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) { if (event == Lifecycle.Event.ON_START) { mCurrentCancellable = addCancellableCallback(mOnBackPressedCallback); } else if (event == Lifecycle.Event.ON_STOP) { if (mCurrentCancellable != null) { mCurrentCancellable.cancel(); } } else if (event == Lifecycle.Event.ON_DESTROY) { cancel(); } } @Override public void cancel() { mLifecycle.removeObserver(this); mOnBackPressedCallback.removeCancellable(this); if (mCurrentCancellable != null) { mCurrentCancellable.cancel(); mCurrentCancellable = null; } } 复制代码
onStart
的时候:mOnBackPressedCallbacks.add(onBackPressedCallback); OnBackPressedCancellable cancellable = new OnBackPressedCancellable(onBackPressedCallback); onBackPressedCallback.addCancellable(cancellable); 复制代码
这里把回退的回调添加到分发对象中。
mCurrentCancellable是一个 OnBackPressedCancellable
对象:
public void cancel() { mOnBackPressedCallbacks.remove(mOnBackPressedCallback); mOnBackPressedCallback.removeCancellable(this); } 复制代码
onStop
的时候:会调用上面的 cancel
, 移除掉这个 callback
onDestroy
的时候:直接调用 LifecycleOnBackPressedCancellable
的 cancel
方法移除回调。
整体的流程图如下:
使用 OnBackPressedDispatcher
处理回退事件优点:
请关注我的微信公众号 【半行代码】