经常会碰到Fragment需要响应activity的onBackPressed事件,对比下三个不同方案
activity在收到onBackPressed事件后,问下对应的fragment,你要不要拦截啊,你要是拦截,我就不管了,你不要拦截我就自己处理了,代码如下
一个FragmentA,有个public的方法,定义自己是否拦截
class FragmentA : Fragment() {
/**
* @return true代表响应back键点击,false代表不响应
*/
fun handleBackPressed(): Boolean {
if ("满足条件") {
return true
} else {
return false
}
}
}
然后activity在收到onBackPressed事件后,调用下fragmentA的判断方法,如果fragment有处理,就交给fragment处理,没有的话,就调用super.onBackPressed方法,关闭activity
class ActivityA : AppCompatActivity() {
override fun onBackPressed() {
if (!fragmentA.handleBackPressed()) {
super.onBackPressed()
}
}
}
这个策略的问题也是很明显
AndroidX库内部,也提供了一个现成的方案,代码如下
class BaseFragment : Fragment() {
override fun onAttach(context: Context) {
super.onAttach(context)
requireActivity().onBackPressedDispatcher.addCallback(this,
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
//这里处理拦截的逻辑
}
})
}
}
系统有一个OnBackPressedDispatcher类,可以直接基于这个类实现onBackPressed的拦截,但是系统这个实现,有个难以接受的地方,最终使我抛弃使用了
先看下系统内部的实现代码
@MainThread
public void onBackPressed() {
Iterator<OnBackPressedCallback> iterator =
mOnBackPressedCallbacks.descendingIterator();
while (iterator.hasNext()) {
OnBackPressedCallback callback = iterator.next();
if (callback.isEnabled()) {
callback.handleOnBackPressed();
//只要callback的enable是true,就算什么都不做,也会强制拦截
return;
}
}
if (mFallbackOnBackPressed != null) {
mFallbackOnBackPressed.run();
}
}
内部会判断callback.isEnabled()
,如果是true,就强制拦截,false就什么都不做,这样设计有什么问题呢?
完全不符合实际场景
真实场景一般是fragment走到特定逻辑了,就需要拦截,没有走到就不拦截,或者随着不同的业务,会动态不断变化,而Android X的设计是,必现提前告诉它们,要不要拦截
不知道设计这个逻辑的人是怎么想的
首先,定义一个拦截的接口
/**
* 监听activity的onBackPress事件
*/
interface BackPressedListener {
/**
* @return true代表响应back键点击,false代表不响应
*/
fun handleBackPressed(): Boolean
}
基类fragment实现这个接口
/**
* 全局通用的基类fragment
*/
abstract class BaseFragment : Fragment(), BackPressedListener {
override fun handleBackPressed(): Boolean {
//默认不响应
return false
}
}
fragmentA需要响应,就override这个方法
class FragmentA : BaseFragment(){
override fun handleBackPressed(): Boolean {
//处理自己的逻辑
return true
}
}
最后在基类activity实现逻辑打通
class BaseActivity : AppCompatActivity() {
override fun onBackPressed() {
if (!interceptBackPressed()) {
super.onBackPressed()
}
}
/**
* 拦截事件
*/
private fun interceptBackPressed(): Boolean {
supportFragmentManager.fragments.forEach {
if (it is BackPressedListener) {
if (it.handleBackPressed()) {
return true
}
}
}
return false
}
}
这个方案总结
综合以上三个,最终选择了方案3,另外希望Android X的实现方案可以早日调整