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的事件分发
阅读完如果觉得哪里有问题或者需要纠正的地方请留言,不甚感激~~~
更多相关文章
- 如何在eclipse的android工程里引用android sdk之外的类和方法
- 深入探讨 Android(安卓)传感器
- Android(安卓)坐标系及动画移动坐标相关集合
- Android中丰富多彩的onTouch事件
- Android获取本机电话号码的简单方法
- 一张图带你掌握Android(安卓)Q上InputDispatcher事件分发流程(系
- Android(安卓)结束进程的方法
- android studio在模拟器上的中文乱码问题解决方法
- Android5.x+ 格式化外部存储(u盘, sdcard)的方法