Android基础_事件分发源码走读

一、带着问题出发  

 我们手触摸点击屏幕的时候,触摸、点击事件是如何分发的呢?

 布局中的控件是如何获取到按键事件的呢?

 布局中有多个控件,如何只让指定的控件接收到相关的事件呢?

二、说在前面

   下面来大体说下事件分发涉及到的几个类和相关方法:

 

Android的事件分发顺序是:Activity ----> ViewGroup ----> View

   涉及到的几个重要方法:

 

  dispatchTouchEvent();

  onInterceptTouchEvent();

  onTouchEvent();

   dispatchTouchEvent负责事件的分发,onInterceptTouchEvent()是ViewGroup中判断是否进行事件拦截的方法,onTouchEvent() 是dispatchTouchEvent() 中执行的方法。

    下面就分别来看下事件在Activity、ViewGroup、View 的分发机制。

三、Activity 的事件分发机制

   Activity.java

public boolean dispatchTouchEvent(MotionEvent ev) {

   if (ev.getAction() == MotionEvent.ACTION_DOWN) {

            onUserInteraction();

   }

    

   // >>> 分析1

   if (getWindow().superDispatchTouchEvent(ev)) {

        return true;

  }

   return onTouchEvent(ev);

}

PhoneWindow.java

@Override

    public boolean superDispatchKeyEvent(KeyEvent event) {

        return mDecor.superDispatchKeyEvent(event);

   }



private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {

 @Override

 public boolean dispatchTouchEvent(MotionEvent ev) {

      final Callback cb = getCallback();

      return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)

                    : super.dispatchTouchEvent(ev);

        }

}



public class FrameLayout extends ViewGroup {

  ...

}

分析1:getWindow()是获取当前的window,调用到的是PhoneWindow,PhoneWindow 的superDispatchKeyEvent()中调用了DecorView 的superDispatchKeyEvent();而DecorView中调用的是super.dispatchTouchEvent(ev);

  DecorView继承的是FrameLayout,FrameLayout又是继承的ViewGroup,所以最终会调用到ViewGroup的dispatchTouchEvent(ev);

 

四、ViewGroup的事件分发机制

 ViewGroup.java

public boolean dispatchTouchEvent(MotionEvent ev) {

   //>>> 分析2

   intercepted = onInterceptTouchEvent(ev);

   ...

   if(dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {

          ...         

        }

  ...

}



public boolean onInterceptTouchEvent(MotionEvent ev) {

   return false;

}



private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,

            View child, int desiredPointerIdBits) {

      if (child == null) {

                handled = super.dispatchTouchEvent(event);

      } else {

                handled = child.dispatchTouchEvent(event);

      }

}

分析2:这里会有intercept,是否进行事件拦截的判断,该值是根据onInterceptTouchEvent()的返回值来判断,默认是返回的fale。

如果需要对事件进行拦截,可以重写ViewGroup的onInterceptTouchEvent()方法,直接return true,onInterceptTouchEvent()方法只有ViewGroup有,Activity和View都没有。

 intercept 值为true,则进行事件拦截,执行的是super.dispatchTouchEvent(event),也就是View的dispatchTouchEvent(ev)方法,这个下面会分析.

 intercept 值为false,则会遍历ViewGroup的子view,如果是处于子View的触摸区域,则会调用子view的dispatchTouchEvent();

 

五、View的事件分发机制

   View.java

public boolean dispatchTouchEvent(MotionEvent event) {

      // >>>分析3

     if (li != null && li.mOnTouchListener != null

                    && (mViewFlags & ENABLED_MASK) == ENABLED

                    && li.mOnTouchListener.onTouch(this, event)) {

                result = true;

      }

      // >>>分析4

      if (!result && onTouchEvent(event)) {

                result = true;

      }

}



public void setOnTouchListener(OnTouchListener l) {

        getListenerInfo().mOnTouchListener = l;

}



 public boolean onTouchEvent(MotionEvent event) {

        ...

        if (mTouchDelegate != null) {

            if (mTouchDelegate.onTouchEvent(event)) {

                return true;

            }

        }



        if (((viewFlags & CLICKABLE) == CLICKABLE ||

                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {

            switch (event.getAction()) {

                case MotionEvent.ACTION_UP:

                  ......

                 if (mPerformClick == null) {

                      mPerformClick = new PerformClick();

                 }

                 

     if (!post(mPerformClick)) {

                       performClick();

                 }

                    break;



                case MotionEvent.ACTION_DOWN:

                   ...

                    break;



                case MotionEvent.ACTION_CANCEL:

                   ...

                    break;



                case MotionEvent.ACTION_MOVE:

                    ...

                    break;

            }

            return true;

        }

        return false;

}



public boolean performClick() {

        final boolean result;

        final ListenerInfo li = mListenerInfo;

        if (li != null && li.mOnClickListener != null) {

            playSoundEffect(SoundEffectConstants.CLICK);

            li.mOnClickListener.onClick(this);

            result = true;

        } else {

            result = false;

        }

         return result;

    }

分析3:如果view设置了OnTouchListener监听,这会会执行OnTouchListener的监听,如果onTouchLister return true,则表示事件被消费掉了,会直接return true,事件分发结束;可以重写setOnTouchListener()方法.

分析4:OnTouchListener中返回false,则会往下执行onTouchEvent(ev)方法,onTouchEvent(ev)中会执行performClick()方法,这时如果view设置了onClick监听,会执行onClick方法。

 这里也可以看到,onTouchListener的执行会先于onClickListener.

 

六、最后总结

        通过上面简单的代码跟读,我们知道点击Activity时,点击事件最先传递到Activity.java dispatchTouchEvent()中进行分发,dispatchTouchEvent()中会调用到ViewGroup 中的dispatchTouchEvent()方法,ViewGroup 中有个重要的onInterceptTouchEvent()方法来判断是否进行事件拦截,该方法默认return false,如果我们希望进行事件拦截,可以重写该方法,return true,则事件会被消费掉,不会再分发给子view;onInterceptTouchEvent() return false的时候,会继续往下走,往下会遍历子view,如果当前点击的区域是相应子view的区域,则会调用到子view的dispatchTouchEvent()方法,view 的dispatchTouchEvent()中会先优先判断是否设置了onTouchListener监听,onTouchListener return false,后面才会执行view 的onClick监听。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
本项目是一个基于SpringBoot开发的华府便利店信息管理系统,使用了Vue和MySQL作为前端框架和数据库。该系统主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的Java学习者,包含项目源码、数据库脚本、项目说明等,有论文参考,可以直接作为毕设使用。 后台框架采用SpringBoot,数据库使用MySQL,开发环境为JDK、IDEA、Tomcat。项目经过严格调试,确保可以运行。如果基础还行,可以在代码基础之上进行改动以实现更多功能。 该系统的功能主要包括商品管理、订单管理、用户管理等模块。在商品管理模块中,可以添加、修改、删除商品信息;在订单管理模块中,可以查看订单详情、处理订单状态;在用户管理模块中,可以注册、登录、修改个人信息等。此外,系统还提供了数据统计功能,可以对销售数据进行统计和分析。 技术实现方面,前端采用Vue框架进行开发,后端使用SpringBoot框架搭建服务端应用。数据库采用MySQL进行数据存储和管理。整个系统通过前后端分离的方式实现,提高了系统的可维护性和可扩展性。同时,系统还采用了一些流行的技术和工具,如MyBatis、JPA等进行数据访问和操作,以及Maven进行项目管理和构建。 总之,本系统是一个基于SpringBoot开发的华府便利店信息管理系统,使用了Vue和MySQL作为前端框架和数据库。系统经过严格调试,确保可以运行。如果基础还行,可以在代码基础之上进行改动以实现更多功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小驰行动派

谢谢老板,今晚吃鸡~

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

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

打赏作者

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

抵扣说明:

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

余额充值