android源码分析之View的事件分发(上)
Posted 古冥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android源码分析之View的事件分发(上)相关的知识,希望对你有一定的参考价值。
1、View的继承关系图
View的继承关系图如下:
其中最重要的子类为ViewGroup,View是所有UI组件的基类,而ViewGroup是容纳这些组件的容器,同时它也是继承于View类。而UI组件的继承关系如上图,比较常用的组件类用红色字体标出。
2、事件
2.1 事件类型
当用户触摸屏幕,根据不同的动作会产生不同的按键事件,如OnClick, OnLongClick, OnTouchEvent等。每个View会重写相应的回调方法,而具体的回调方法则是在View类中进行了定义,如OnLongClick见View的源码如下:
public interface OnLongClickListener
/**
* Called when a view has been clicked and held.
*
* @param v The view that was clicked and held.
*
* @return true if the callback consumed the long click,
* false otherwise.
*/
boolean onLongClick(View v);
而具体的事件类型主要有如下三类:
MotionEvent.ACTION_DOWN //按下View,是所有事件的开始
MotionEvent.ACTION_MOVE //滑动事件
MotionEvent.ACTION_UP //与down对应,表示抬起
2.2 事件响应机制
1>注册一个监听对象。
2>实现监听对象的监听事件,即事件分发时的回调方法。
3>当某一触发事件到来,在触发事件中通过注册过的监听对象,回调注册对象的响应事件,来完成用户自定义实现。
注:具体的实现过程见第三节。
3、View的事件分发
3.1 ViewRootImpl的创建过程分析
这里介绍一个重要的类:ViewRootImpl类
简单来说,ViewRootImpl相当于是窗口系统中的MVC模型中的Controller,它的主要职责为:
1. 负责为应用程序窗口视图创建Surface。
2. 配合WindowManagerService来管理系统的应用程序窗口。
3. 负责管理、布局和渲染应用程序窗口视图的UI。
ViewRootImpl有两个创建时机:
1>Activity组件在启动的时候,系统会为它创建窗口对象(Window),同时,系统也会为这个窗口对象创建ViewRootImpl对象。
2>当Activity组件被激活的时候,系统如果发现与它的应用程序窗口视图对象所关联的ViewRoot对象还没有创建,那么就会先创建这个ViewRoot对象,以便接下来可以将它的UI渲染出来。
ViewRootImpl的创建时序图如下:
此处不做详细分析,由时序图即可看出大概流程。
3.2 View事件处理对象ViewPostImeInputStage的注册过程分析
此处先分析ViewRootImpl类的setView方法:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView)
...
res = mWindowSession.addToDisplay(mWindow, mSeq,
mWindowAttributes,getHostVisibility(),
mDisplay.getDisplayId(),
mAttachInfo.mContentInsets,
mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
...
// Set up the input pipeline.
CharSequence counterSuffix = attrs.getTitle();
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage =
new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage =
new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage =
new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage =
new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage =
new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage =
new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
...
由以上代码可知,setView方法中会建立输入管道,此处采用责任链模式,即触摸事件最终还是要分发给具体的View来处理的,所以最后对事件的处理会由此责任链来负责,而此责任链在此预先注册了的InputStage主要有SyntheticInputStage、ViewPostImeInputStage、NativePostImeInputStage、EarlyPostImeInputStage、ImeInputStage、ViewPreImeInputStage、NativePreImeInputStage等。此处只分析ViewPostImeInputStage,至于其他的自行分析。
本文假设读者已经预先了解了android的输入子系统,所以本文不解释输入子系统的工作原理。
在Input子系统的native层socket客户端读取输入事件,最终调用InputEventReceiver类子类的onInputEvent()方法,ViewRootImpl的setView方法中初始化了WindowInputEventReceiver对象,它继承自类InputEventReceiver。
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
其中mInputChannel与Input输入子系统建立了联系,所以最终会调用WindowInputEventReceiver的onInputEvent()方法。
3.3 View的事件分发流程分析
在3.2节中分析了处理ViewPostImeInputStage的注册,以及ViewRootImpl中响应输入事件的入口,本小节将继续分析事件的分发流程:
此时序图分析了View事件中的OnClick事件的分发过程,由图可知,ViewRootImpl截取到事件后会分发给ViewPostImeInputStage处理,而ViewPostImeInputStage接着将事件分发给具体的View,此时根据View里面注册的监听事件,调用其回调函数,最终响应我们自定义的操作。至此,View的事件分发分析结束。
以上是关于android源码分析之View的事件分发(上)的主要内容,如果未能解决你的问题,请参考以下文章
Android 事件分发事件分发源码分析 ( ViewGroup 事件传递机制 四 | View 事件传递机制 )
Android查缺补漏(View篇)--事件分发机制源码分析
Android 事件分发事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 )
朝花夕拾Android自定义View篇之Android事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象