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事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象

Android 源码解析View的touch事件分发机制

源码阅读分析 - View的Touch事件分发