Android 事件流详解之View事件分发

一.前言

       刚学习Android的朋友们可能以会使用控件为主要任务,但是我们随着学习Android的深入,会不断接触到Android的事件流,也就是Android的事件分布机制.可能有些人觉得这和你有什么关系,你可能觉得不了解我照样做app,但是博主建议你还是熟悉它比较好,因为博客学习Android的时候,需要熟悉它的时候有以下几种:

1.自定义控件的时候

2.在某些情况下的bug,比如ListView的OnItemClickListener的onItemClick方法失效

3.某些情况下要获取用户的按键情况,比如你想屏蔽后退键

还有其他的一些情况,博客暂时想到的就这些了,不过肯定还有其他你需要熟悉它的时候


今天博客就重点基于Android 6.0的源码,解析一下事件的分发机制

首先先引用别人的一张我们看到的视图层次机构图,因为博主自己画就太丑了,哈哈


从这里我们可以看出,ViewGroup是一个容器,它可以承载View或者其他的ViewGroup容器,而ViewGroup本身又继承了View,所以ViewGroup是View的一个扩展.这是对上图的一个简单的介绍,好了,下面是正文

二.解析View的事件分发

首先贴出View的事件分发的主要源代码

    public boolean dispatchTouchEvent(MotionEvent event) {
        
        boolean result = false;

        final int actionMasked = event.getActionMasked();

        //安全性的拦截方法,检查view是不是被覆盖了
        if (onFilterTouchEventForSecurity(event)) {
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }

        return result;
    }
       //在事件分发的时候做一个安全性的检测,检测View是不是被遮盖,如果被遮盖返回false,否则返回true,true表示应该分发事件
    public boolean onFilterTouchEventForSecurity(MotionEvent event) {
        //noinspection RedundantIfStatement
        if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0
                && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) {
            // Window is obscured, drop this touch.
            return false;
        }
        return true;
    }


部分无关紧要的代码已经剔除,不然代码不仅长,而且牵扯太多其他的东西

从上面的代码我们看到了View的事件分发,在分发的时候,我们可以清楚的看到调用了一

个检测安全性的方法,如果通过了才可以分发事件.检测啥,上面我已经清除的注释了,这里

不再陈述.

紧接着程序拿到一个ListenerInfo对象,这个对象是什么呢?从字面上理解,应该是一个有关监听的信息的类,那我们就去查看一下

static class ListenerInfo {
	protected OnFocusChangeListener mOnFocusChangeListener;
	private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
	protected OnScrollChangeListener mOnScrollChangeListener;
	private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;
	public OnClickListener mOnClickListener;
	protected OnLongClickListener mOnLongClickListener;/
	protected OnContextClickListener mOnContextClickListener;
	protected OnCreateContextMenuListener mOnCreateContextMenuListener;
	private OnKeyListener mOnKeyListener;
	private OnTouchListener mOnTouchListener;
	private OnHoverListener mOnHoverListener;
	private OnGenericMotionListener mOnGenericMotionListener;
	private OnDragListener mOnDragListener;
	private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
	OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
}

一看,原来是一个接口保存的'仓库'啊,我们可以看到View有关的监听是不是都在里头了呢,点击事件,长按事件。。。。,很多很多,应该是为了避免在View中写太多的成员变量,所以才分离出来的

那我们上面的代码就可以看懂啦!过了安全的检测之后就是四个判断


1.判断保存接口信息的li是不是为空

2.li里面的mOnTouchListener接口是不是为空,说白了也就是你有没有设置这个View的触摸事件

3.View是不是不能用的状态,默认是可用的,通过xx.setEnabled(false)就可以设置成无用的状态啦

4.触摸接口mOnTouchListener的方法onTouch返回的是不是true


这里也就很清楚的看到了,View通过设置监听回调的mOnTouchListener的触摸事件onTouch是比View的其他事件都要早的,如果你监听了该事件,那么你就有绝对的权利控制事件是否能流到其他的地方


       如果在设置的触摸接口的回调方法onTouch方法中返回了一个true,那么变量result就会被置为true,所以下面的View自身的onTouch事件将不会再被调用,反之View自身的onTouchEvent事件被调用,而View的点击事件就是在onTouchEvent方法中调用的,所以View的点击事件如果失效了,就针对View本身来说有如下可能:

1.事件被mOnTouchListener的方法onTouch消费了,也就是这里返回的是true

2.你重写View的onTouchEvent方法的时候没有调用super.onTouchEvent(e)方法


下一篇介绍ViewGroup的事件分发

阅读完如果觉得哪里有问题或者需要纠正的地方请留言,不甚感激~~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值