前言 当我们在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 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去处理按键返回事件,更加关注于自身业务逻辑的编写,减少样本代码,并且早已被加入了正式版本,可以在考虑在实际开发中大胆使用。 |