重学input:为什么要进行二次拦截?interceptKeyBeforeQueueing和interceptKeyBeforeDispatching 区别

背景:

前几天也有vip学员朋友在群里问道了关于系统Key拦截部分的问题,大概就是在 Android 输入事件处理流程中,interceptKeyBeforeQueueing 和 interceptKeyBeforeDispatching 是两个关键的系统级拦截方法,那么同样为系统级别拦截事件方法,请问他们有什么差异呢?为什么系统中要搞两个拦截呢?具体自己编写相关拦截业务时候应该如何考虑在哪个方法进行拦截呢?
针对上面疑问本节会对系统中拦截事件两个方法进行详细对比

1. 触发阶段

方法名
interceptKeyBeforeQueueing

触发阶段

事件入队前
(系统将按键事件放入全局队列前)

方法名
interceptKeyBeforeDispatching

触发阶段

事件分发前
(系统准备将事件分发给目标窗口前)

3. 典型应用场景

interceptKeyBeforeQueueing - 电源键亮屏/灭屏

  • 音量键调节全局音量
  • 截屏快捷键(如 Power + Vol-)

interceptKeyBeforeDispatching

  • HOEM按键
  • 应用内自定义快捷键(如 Ctrl+S 保存)

4. 代码逻辑对比

interceptKeyBeforeQueueing部分:
方法原型

 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) 

可以看出比较简单,就一个event,还有一个policyFlags

代码比较多,这里以POWER电源按键为例进行展示代码分析:
在这里插入图片描述上面代码就看出了,只要是POWER按键,result就会排除掉ACTION_PASS_TO_USER这个值,返回InputDispatcher后就靠这个值来确定是否拦截,一般有ACTION_PASS_TO_USER这个值就代表不拦截。

interceptKeyBeforeDispatching 部分:

方法原型:

public long interceptKeyBeforeDispatching(IBinder focusedToken, KeyEvent event,
            int policyFlags) 

明显可以看出这里多了一个窗口相关focusedToken参数,主要就是拦截相关逻辑需要结合窗口。

这里以HOME按键为例进行展示代码分析:

interceptKeyBeforeDispatching的方法主要会调用到interceptSystemKeysAndShortcuts
在这里插入图片描述下面看看interceptSystemKeysAndShortcuts方法
在这里插入图片描述下面来来看看handleHomeShortcuts方法

   private boolean handleHomeShortcuts(IBinder focusedToken, KeyEvent event) {
     //省略
        return handler.handleHomeButton(focusedToken, event);
    }

上面方法主要又是调用到handler.handleHomeButton方法

 boolean handleHomeButton(IBinder focusedToken, KeyEvent event) {
         //省略部分
         
                //通过focusedToken获取相关窗口信息
            final KeyInterceptionInfo info =
                    mWindowManagerInternal.getKeyInterceptionInfoFromToken(focusedToken);
            if (info != null) {
                // If a system window has focus, then it doesn't make sense
                // right now to interact with applications.
                //判断是否窗口类型为锁屏相关,如果是就不拦截事件
                if (info.layoutParamsType == TYPE_KEYGUARD_DIALOG
                        || (info.layoutParamsType == TYPE_NOTIFICATION_SHADE
                        && isKeyguardShowing())) {
                    // the "app" is keyguard, so give it the key
                    return false;
                }
                for (int t : WINDOW_TYPES_WHERE_HOME_DOESNT_WORK) {
                    if (info.layoutParamsType == t) {
                        // don't do anything, but also don't pass it to the app
                        return true;
                    }
                }
            }
            
         //省略部分

handleHomeButton方法中就有核心逻辑,会有不拦截HOME按键的场景,具体会有如下代码逻辑:

1、通过focusedToken获取到对应的window相关信息

2、判断窗口类型是不是锁屏相关的,如果是锁屏相关窗口,切显示者,则直接不拦截

总结

interceptKeyBeforeQueueing:

最开始的事件拦截,也就是拦截的优先级最高,系统级“紧急开关”,确保全局按键(如电源键)立即生效,无需等待应用响应,事件也压根不会传递给应用。

interceptKeyBeforeDispatching:

如果interceptKeyBeforeQueueing方法不拦截该事件,那么就开始准备派发给应用,会先获取当前的FocusWindow,在派发应用前进行事件相关事件拦截。应用级“筛选器”,根据当前窗口状态决定是否将事件传递给应用,比如HOME按键按下时候,就会考虑当前是否为锁屏画面。

两者的协同工作,保证了 Android 系统既能快速响应关键操作,又能灵活处理应用层交互。

更多framework实战干货,请关注下面“千里马学框架”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值