前言 当我们在fragment 中处理返回键事件的时候,很多时候做法都是这样的:Activity 中重写onBackPressed() ,在此方法中获取当前的fragment 对象,判断是否要处理返回事件,如果需要处理,就交由fragment 再去具体响应返回事件,大致代码如下: interface BackPressedListener {
fun onBackPressed(): Boolean
}
class ExampleFragment : Fragment(), BackPressedListener {
override fun onBackPressed(): Boolean {
return if (handleBackPress) {
// 具体处理事件
true
} else {
false
}
}
}
class ExampleActivity : AppCompatActivity() {
override fun onBackPressed() {
val currentFragment = getCurrentFragment()
if (!currentFragment.onBackPressed()) {
super.onBackPressed()
}
}
} 这种写法确实能够解决问题,并且可能是我们目前正在使用的,唯一不足就是稍显繁琐,需要开发者自行实现接口,拦截事件,写一些样板代码。 新方案 也许是谷歌终于意识到上面的方案并没有十分优雅,终于在 androidx.activity: 1.1.0 中引入了OnBackPressedDispatcher 类,以供开发者在fragment 中相对简单的处理返回按键事件。具体使用方式: class ExampleFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
requireActivity().onBackPressedDispatcher.addCallback(
//这个LifecycleOwner可以不用也行
//viewLifecycleOwner,
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (handleBackPress) {
// 具体执行返回事件
} else {
isEnabled = false
requireActivity().onBackPressed()
}
}
})
}
} 上面的代码是不是看起来要简单一些了,至少目前看起来是的。这段代码主要利用Activity 来获取一个OnBackPressedDispatcher 对象,然后再往里面添加一个callback ,负责去处理具体的返回事件逻辑。这样,我们只用在fragment 中添加了代码了,而越少的代码就意味着更少的错误的可能😂。 问题 1. 为什么要在添加的callback 中传入true ,有什么具体作用吗? 首先先来看一下此方案的实现思路:首先在ComponentActivity 中重写了onBackPressed() ,并将逻辑委托给了OnBackPressedDispatcher ,用于具体响应和分发事件。在OnBackPressedDispatcher 中使用了一个双端队列mOnBackPressedCallbacks 存储各个callback ,当我们点击返回键时,就会开始遍历这个队列,找到处于激活状态(mEnable 为 true)的那个callback ,将事件交由它处理,实际上思路和第一种方式是类似的,只不过官方帮我们将整个过程简化了。 @MainThread
public void onBackPressed() {
Iterator<OnBackPressedCallback> iterator =
mOnBackPressedCallbacks.descendingIterator();
while (iterator.hasNext()) {
OnBackPressedCallback callback = iterator.next();
if (callback.isEnabled()) {
callback.handleOnBackPressed();
return;
}
}
if (mFallbackOnBackPressed != null) {
mFallbackOnBackPressed.run();
}
} 所以callback 中传入的true 参数就很好理解了,用于控制当前callback 是否处于激活状态,aka 是否响应返回事件。 2. 既然调用了addCallback 函数添加了callback ,是否还需要开发者去调用remove 呢? 可以从上面的代码中看到,在添加callback 的时候同时也是传入了lifecycleOwner 对象的,也就意味为这一套BackPressedDispatcher 机制是对生命周期敏感的,会自行根据当前生命周期进行处理。查看源码,也印证了这一结论。 private class LifecycleOnBackPressedCancellable implements LifecycleEventObserver,
Cancellable {
// ...省略代码
@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) {
// Should always be non-null
if (mCurrentCancellable != null) {
mCurrentCancellable.cancel();
}
} else if (event == Lifecycle.Event.ON_DESTROY) {
cancel();
}
}
// ... 省略代码
} 3. 上面的代码中为什么需要手动将isEnable 置为 false,并调用Activity 的onBackPressed 函数? 从ComponentActivity 中的onBackPressed 函数中可以看到,实际上在循环中找到isEnable 为 true 的callback 并将其处理返回之后,这一次返回点击就已经结束了,如果我们此时并不需要拦截返回事件,则需要重置isEnable 状态,重新去寻找下一个处理事件的callback 或者直接让Activity 去处理。 结论 OnBackPressedDispatcher 的出现,可以让开发者相对优雅的在fragment 去处理按键返回事件,更加关注于自身业务逻辑的编写,减少样本代码,并且早已被加入了正式版本,可以在考虑在实际开发中大胆使用。 |