13.1概述
概念:View系统定义了从用户输入消息到处理消息的全部过程。【本文是基于Android 2.3.3源码来进行分析】
简述事件处理的流程
-
1、【事件产生】用户通过触摸屏或者键盘等输入设备产生输入消息,该消息首先被消息处理前端进行接收。
-
2、【事件封装】消息处理前端接收到该消息后进行一个明确的消息转换,比如”按下”、”抬起”消息,并且该消息包含了原始的键盘码值,该值是由硬件系统决定的,不同的硬件系统会产生不同的消息值。之后消息继续传递至消息处理模块。
-
3、【内容统一映射】消息处理模块需要一个统一的消息值,例如字符值。消息处理前端的作用就是将这些特定的硬件消息转换成操作系统所需要的统一值。
-
4、【事件分发】WindowManagerSrevice根据所有的窗口状态判断用户正在与哪个窗口进行交互,然后将该消息发送给当前窗口。
-
4.1、如果是按键消息,则直接发送给当前窗口
-
4.2、如果是触摸消息,则WindowManagerSrevice会根据消息的位置坐标去匹配所有的窗口,判断该坐标落到了哪个窗口的区域中,然后把该消息发送给相应的窗口。
-
-
5、【事件处理】消息达到了目标窗口,该窗口内部是怎样处理的就是根据不同的GUI系统来拟定了。应用程序一般不直接处理该消息,而是重载一些特定的方法或实现一些特定的回调函数。操作系统在调用应用程序,而不是应用程序在调用操作系统。
-
6、【View系统】View系统获得消息后,会按照默认的逻辑来进行派发消息(Touch消息传递机制),主要就是把该消息派发给所有的子View,以便相应的子View能够获得消息并执行不同任务,如果该任务会引起界面的变化,那么View系统则要重新绘制界面。
简述绘制流程
-
1、计算该窗口中所有View的大小——Measure。
注意:并不是所有导致界面重绘的操作都需要重新计算窗口的大小,在View的内部逻辑中,使用了一个内部变量保存相应的状态,当用户的某个操作导致了改变了View大小时,会设置该变量,而View的内部逻辑会根据该变量,决定是否需要重新测量。 -
2、为所有的View分配位置——Layout。
-
3、把View绘制到屏幕上——Draw。
在绘制时,系统内部为每个窗口创建了一个Canvas对象,并把这个Canvas对象传递给从ViewRoot到所有的子View。View系统将Canvas传递给子View时,都先将对该Canvas进行一次Clip,从而在子View看来,总是从Canvas的(0,0)开始绘制的。
13.2用户消息类型
经过消息处理前端把硬件物理消息转换成Framework内部定义的统一格式后的消息。该消息目前分为三类:
按键消息
android.view.KeyEvent
该类定义了消息包含的参数以及获取这些参数的API。
-
getAction()
- 返回按键动作,只有两种动作,DOWN和UP。
-
getKeyCode()
- 返回按键代码,这些代码是Android内部统一定义的,原始消息必须被转换成此代码才能被Framework处理。
- 该函数还可以用来处理组合键,处理时先调用getKeyCode()获取具体的键值,然后调用isShiftPressed()、isAltPressed()、isSymPressed()等分别判断是否有组合键按下。
-
getRepeat()
- 返回从按下后重复的次数。
触摸消息
android.veiw.MotionEvent
该类定义了和触摸相关的消息参数,并提供了一组API让用户来获取这些参数。
-
getAction():
- 获取消息动作,该消息中包含是哪个点按下或者释放。
-
getEventTime()和getDownTime()
- 获取本次消息发生的时间,
- 获取Down消息发生的时间,如果本次消息就的DOWN消息,两者相同,如果本次不是DOWN消息,那么则为前 面最后一次Down消息发生的时间。
-
getPressure()
- 获取用户点击力量的大小,其值可以大于1.
-
getSize()
- 该函数仅用于电容屏,反映了用户触摸面积的大小,其至在0~1之间。
-
getX(int index) 和getY(int index)
- 返回指定触摸点对应的坐标,对于多点触控而言,参数index代表哪个点,从0开始。
多点触摸过程对应的事件
对于更多的点触碰,叹气的顺序不同将产生不同的ACTION序列,这些序列的规矩有两个:
- 1、如果 5【1】已经弹起ACTION_POINTER_UP1,那么后续的 5【2】ACTION都对应该5【1】,也就是实质上现在的Pointer已经为 4【1】代表之前的5【2】点,此时如果4【1】弹起的事件为ACTION_POINTER_UP1。
- 2、最后一个点弹起时,直接发送 ACTION_UP。
弊端:尽管应用程序可以获得多点触控的消息,然而在目前的View系统中(2.3),并未提供多点触控的标准消息处理。
触摸消息派发过程
- 触摸消息是消息获取模块直接派发给应用程序的。
- 触摸消息在处理时,需要根据触摸坐标计算该消息应该派发给哪个View。
- 应用程序可完全控制触摸行为
- 子View优先父View处理消息,即首先是子View处理该消息,只有当子View消耗该消息时,父View才有机会处理。
触摸消息总体派发过程
点击下载
1. MessageQueue 中的next()函数内部调用 nativePollOnce() 读取触摸消息。
2. 如果有消息,回调 ViewRoot 内部的 mInputHandler 对象的 dispatchMotion(),该函数仅仅是发起一个 DISPATCH_POINTER 的异步消息。
3. DISPATCH_POINTER消息交付由 deliverPointerEvent() 来进行处理。
4. 执行完 deliverPointerEvent() 后,调用 finishInputEvent() 向消息获取模块发送一个回执,以便其进行下一次消息派发,真正完成回执的代码是由native C++编写的。