Android进阶知识树——View、ViewGroup事件分发机制详解

本文详细探讨了Android开发中View和ViewGroup的事件分发机制,从源码层面分析了dispatchTouchEvent(), onTouchEvent(), onInterceptTouchEvent()等关键方法的执行流程。了解这些机制对于解决滑动冲突至关重要,文中还介绍了如何在外部和内部进行事件拦截,以应对不同类型的滑动冲突问题。" 84257693,7886445,ETL技术笔试题:数据处理与银行业务知识测试,"['数据库理论', '数据结构', '算法', '项目管理与协作工具', '开发工具']

对于Android开发者来说,自定义View是必须攻克的一关,也是从初级工程师迈向高级的进阶关卡,要想通过此阶段,除了必须掌握View的测量、绘制、滑动等基础知识外,更要掌握View的核心知识点:View的事件分发,本篇就一起从源码的角度分析View和ViewGroup的事件分发机制;

1、View的事件分发

在我们平时的使用或写自定义View时,都会直接或间接的使用View的事件分发,View的事件分发主要与View源码中的3个方法有关:

  1. dispatchTouchEvent()
  2. onTouch()
  3. onTouchEvent()

下面我们针对这三个方法从源码学习和分析事件的分发,一起从本质上掌握View是如何在层层传递和消耗事件;

  • dispatchTouchEvent(MotionEvent event)
public boolean dispatchTouchEvent(MotionEvent event) {
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
        && (mViewFlags & ENABLED_MASK) == ENABLED
        && li.mOnTouchListener.onTouch(this, event)) {
    result = true;
}
if (!result && onTouchEvent(event)) {
    result = true;
}
}

上面代码是dispatchTouchEvent()中的部分代码,也是与我们使用最接近的核心代码,首先会判断View是否设置触摸监听mOnTouchListener,如果设置则会调用OnTouchListener.onTouch()方法,如果此方法返回true,则dispatchTouchEvent()返回true即拦截事件,若onTouch()返回false,则调用onTouchEvent(),如果onTouchEvent()返回true则事件被消耗,否则事件继续传递;从上面的方法和叙述我们可以得出以下结论:

  1. 若View设置OnTouchListener,则先调用onTouch(),所以OnTouchListener的优先级高于onTouchEvent()
  2. 若onTouch()返回true,表示onTouch消耗事件,此时onTouchEvent()不会调用
  3. 若onTouch()返回false,此时onTouchEvent()被调用,若onTouchEvent返回true,事件被消耗

1.1、onTouchEvent()源码分析

  • ACTION_DOWN:
if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) {
    mPrivateFlags3 |= PFLAG3_FINGER_DOWN; // 设置mPrivateFlags3为FINGER_DOWN标记
}
mHasPerformedLongPress = false;  //设置false表示此事还未出发长按事件

boolean isInScrollingContainer = isInScrollingContainer();  // 调用父容器的shouldDelayChildPressedState(),默认true

if (isInScrollingContainer) {
    mPrivateFlags |= PFLAG_PREPRESSED; // 状态设置为中间状态PFLAG_PREPRESSED
    if (mPendingCheckForTap == null) {
        mPendingCheckForTap = new CheckForTap();
    }
    mPendingCheckForTap.x = event.getX();
    mPendingCheckForTap.y = event.getY();
    postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); // 延时发送执行CheckForTap中的run(),ViewConfiguration.getTapTimeout() = 100ms
} else {
    setPressed(true, x, y);
    checkForLongClick(0, x, y); // 直接检测长按事件
}

//CheckForTap中调用检测长按事件
@Override
public void run() {
    mPrivateFlags &= ~PFLAG_PREPRESSED;
    setPressed(true, x, y);
    checkForLongClick(ViewConfiguration.getTapTimeout(), x, y);//调用长按检测方法
}

// checkForLongClick中延时发送CheckForLongPress实例
postDelayed(mPendingCheckForLongPress,
        ViewConfiguration.getLongPressTimeout() - delayOffset);  // getLongPressTimeout()为 500ms(系统默认的长按时间)

@Override
public void run() {
    if ((mOriginalPressedState == isPressed()) && (mParent != null)
            && mOriginalWindowAttachCount == mWindowAttachCount) {
        if (performLongClick(mX, mY)) {  // 
            mHasPerformedLongPress = true;  // 设置标志表示触发长按;此标志是否为true取决于li.mOnLongClickListener.onLongClick的返回值
        }
    }
}

//在performLongClick()中代码会最终调用performLongClickInternal()
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnLongClickListener != null) {
    handled = li.mOnLongClickListener.onLongClick(View.this);  //调用长按监听中的onLongClick();返回值影响mHasPerformedLongPress
}

以上代码是View的onTouchEvent()的ACTION_DIOWN执行逻辑,只粘贴了部分关键代码,所执行逻辑如上面注释,下面我们逐步分析以下:

  1. 首先将mPrivateFlags3设置为FINGER_DOWN标记
  2. 将mHasPerformedLongPress设置为false,表示点击还未触发长按事件
  3. 创建CheckForTap()实例,并延时发送执行CheckForTap中的run()
  4. 在checkForLongClick中延时发送CheckForLongPress实例,检测长按事件
  5. 在performLongClick()中代码会最终调用performLongClickInternal(),performLongClickInternal回调设置的mOnLongClickListener.onLongClick()
  6. 若onLongClick()返回tr
内容概要:本文围绕VSG构网型逆变器与跟网型逆变器之间的双向平滑切换控制策略展开深入研究,系统探讨了GFL(跟网型)与GFM(构网型)逆变器在并网与孤岛运行模式下的切换机制。基于Simulink平台构建仿真模型,详细实现了切换过程中的控制逻辑设计、系统稳定性保障及动态响应性能优化等关键技术环节,重点解决模式切换过程中可能出现的电流冲击、频率电压波动等问题,确保微电网在不同运行工况下的连续稳定运行。研究还融合事件触发机制与分布式二次控制策略,实现频率和电压的无差调节,并提升通信资源受限或遭受DoS攻击等异常情况下的系统弹性与协同控制能力,适用于高比例新能源接入场景下的微电网灵活运行需求。; 适合人群:具备电力电子、自动控制、微电网与新能源系统等相关专业背景,从事电力系统仿真、分布式能源控制研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①深入理解构网型与跟网型逆变器的运行机理及切换控制原理;②设计并仿真验证GFL/GFM模式间的双向平滑切换策略;③应用于微电网分层控制、孤岛检测与无缝切换、二次频率电压恢复等实际工程场景;④支撑IEEE Transactions等顶级期刊论文的复现、科研项目开发及创新性课题研究。; 阅读建议:建议结合提供的Simulink仿真模型同步学习,重点关注模式切换判据、控制架构切换逻辑、事件触发条件设定及控制器参数整定方法,配合网盘中的完整代码与模型资源进行仿真调试,以深入掌握其实现细节并开展进一步的优化与拓展研究。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值