# Android View的事件分发 分析源码

引言

从Android底层开始分析View的事件分发至上层FrameWork。

分两部分来说:

  • 触碰屏幕传递事件至当前Activity.
  • Activtiy传递事件至触碰到的View 或者 ViewGroup

触碰屏幕传递事件至当前Activity

触摸事件是由Linux内核的一个Input子系统来管理的(InputManager),Linux子系统会在 /dev/input/ 这个路径下创建硬件输入设备节点(这里的硬件设备就是我们的触摸屏了)。当手指触动触摸屏时,硬件设备通过设备节点像内核(其实是InputManager管理)报告事件,InputManager 经过处理将此事件传给 Android系统的一个系统Service,这个Service叫WindowManagerService。之后WindowManagerService会将事件传递到PhoneWindow.

可以参考下图, WindowManagerService连接PhoneWindow的过程.

Touch.jpg

WindowManagerService调用dispatchPointer()从存放WindowState的z-order顺序列表中找到能接收当前touch事件的 WindowState,通过IWindow代理将此消息发送到IWindow服务端(IWindow.Stub子类),这个IWindow.Stub属于ViewRoot(这个类继承Handler,主要用于连接PhoneWindow和WindowManagerService),所以事件就传到了ViewRoot.dispatchPointer()中.

看下ViewRoot.dispatchPointer method

ViewRoot_dispatchPointer.jpg

你可以看到通过用Message将DISPATCH_POINTER事件发送出去,处理事件应该在handleMessage method里.

看下ViewRoot.handleMessage method

ViewRoot_handleMessage.jpg

看下ViewRoot.deliverPointerEvent method

ViewRoot_deliver.jpg

最终你会发现调用mView.dispatchTouchEvent(event)
(mView是一个PhoneWindow.DecorView对象),PhoneWindow.DecorView继承FrameLayout(FrameLayout继承ViewGroup,ViewGroup继承自View),DecorView里的dispatchTouchEvent方法如下. 这里的Callback的cb其实就是Activity的attach()方法里的设置回调。

看下PhoneWindow.DecorView dispatchTouchEvent method

DecprdView_dispatchTouchEvent.jpg

回调cb就代表Activity,回调会在Activity的onAttach的时候进行设置.

Activity_onAttach.jpg

再看cb执行dispatchTouchEvent method.即执行Activity的dispatchTouchEvent,之后Activity会把事件又重新传递到DecorView,然后会调用父类(ViewGroup)的dispatchTouchEvent 将事件传给父类处理。即调用ViewGroup 和 View的事件分发机制。

总算绕回到View ViewGroup的事件分发机制。


View 或者 ViewGroup的事件分发机制

事件的概念

在Android中,事件主要包括点按、长按、拖拽、滑动等,点按又包括单击和双击,另外还包括单指操作和多指操作。所有这些都构成了Android中的事件响应。

事件分为三种:

  • 按下(ACTION_DOWN)
  • 移动(ACTION_MOVE)
  • 抬起(ACTION_UP)

ViewGroup和View的分发

相关函数:

  • ViewGroup

    1. public boolean dispatchTouchEvent(MotionEvent event)
    2. public boolean onTouchEvent(MotionEvent event)
    3. public boolean onInterceptTouchEvent(MotionEvent event)
  • View

    1. public boolean dispatchTouchEvent(MotionEvent event)
    2. public boolean onTouchEvent(MotionEvent event)

ViewGroup和View的事件分发是向下传递的,即ViewGroup会一层层向子View分发事件,直到消费事件或者被丢弃。由此可以看出ViewGroup和View相关函数的返回类型都是Boolean,可以直到Boolean类型决定了某一事件是否是继续往下传,还是被拦截了,或是被消费了。

ViewGroup和View的相关函数都接受参数MotionEvent类型的参数,MotionEvent继承于InputEvent,用于标记各种动作事件。之前提到的ACTIONDOWN、ACTIONMOVE、ACTION_UP都是MotinEvent中定义的常量。我们通过MotionEvent传进来的事件类型来判断接收的是哪一种类型的事件。

ViewGroup继承View,即ViewGroup是一个特殊的View,ViewGroup在事件分发中比View多一个函数, onInterceptTouchEvent函数(拦截事件的函数),顾名思义,就是在ViewGroup一层就将事件拦截下来进行处理。

所以一共是三个函数,我们来总结下三个函数的功能:

  • dispatchTouchEvent方法用于事件的分发,Android中所有的事件都必须经过这个方法的分发,然后决定是自身消费当前事件还是继续往下分发给子控件处理。返回true表示不继续分发,事件没有被消费。返回false则继续往下分发,如果是ViewGroup则分发给onInterceptTouchEvent进行判断是否拦截该事件。

  • onTouchEvent方法用于事件的处理,返回true表示消费处理当前事件,返回false则不处理,交给子控件进行继续分发。

  • onInterceptTouchEvent是ViewGroup中才有的方法,View中没有,它的作用是负责事件的拦截,返回true的时候表示拦截当前事件,不继续往下分发,交给自身的onTouchEvent进行处理。返回false则不拦截,继续往下传。这是ViewGroup特有的方法,因为ViewGroup中可能还有子View,而在Android中View中是不能再包含子View的(iOS可以)。

流程简述:

1.ViewGroup执行dispatchTouchEvent进行分发事件,可以进行拦截或者向下分发给子View。如果拦截事件则执行自己的onTouchEvent。
2.子View接受到事件执行dispatchTouchEvent,在这之中如果设置了Listener监听器,则先执行onTouch方法,然后执行onTouchEvent方法。
然后事件被消费结束。

补充如果子View的Listener监听器重写的onTouch方法返回true,则不会继续执行onTouchEvent方法,如果返回false则表示没有消费结束,继续执行onTouchEvent方法。


总结

  • 底层将触摸事件传递到上层的Activity,Activity再传递到ViewGroup,ViewGroup拦截或者不拦截,不拦截则传递分发到子View进行消费,如果这个事件一直没被消费则自动被丢弃。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容