android源码分析之View的事件分发(上)

1、View的继承关系图


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的事件分发分析结束。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值