一种新的在 fragment 中处理按键返回的方法

前言

当我们在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,并调用ActivityonBackPressed函数?

ComponentActivity中的onBackPressed函数中可以看到,实际上在循环中找到isEnable为 true 的callback并将其处理返回之后,这一次返回点击就已经结束了,如果我们此时并不需要拦截返回事件,则需要重置isEnable状态,重新去寻找下一个处理事件的callback或者直接让Activity去处理。

结论

OnBackPressedDispatcher的出现,可以让开发者相对优雅的在fragment去处理按键返回事件,更加关注于自身业务逻辑的编写,减少样本代码,并且早已被加入了正式版本,可以在考虑在实际开发中大胆使用。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值