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

  • 相关阅读:
    手把手教你下载XShell免费版(超详细)
    博客园又崩了,这个锅要不要阿里云背?
    pytorch之文本篇项目——聊天机器人(一)数据预处理
    Golang起步篇(Windows、Linux、mac三种系统安装配置go环境以及IDE推荐以及入门语法详细释义)
    LCA几种算法
    自定义视频播放器
    Feign远程调用
    开源云管平台有哪些?有哪些优势?
    Python面向对象 —— 类属性「二」(属性获取机制和陷阱、代码示例、执行流程分析)
    3. Exchange 交换机的使用
  • 原文地址:https://blog.csdn.net/Goals1989/article/details/133690157