Android事件分发——知其然

前言

很久之前看了些长篇大论的文章之后,只是去死记硬背的记住一些结论,后面不常用也是忘得一干二净;最近闲研究了一番,记录下当时是以什么样的姿势(思路)去了解的。这里不是从源码的角度上进行分析,而是从现象分析猜其分发机制的逻辑,并得出的结论,得到结论之后有时间再去分析源码相对会容易些。这篇文章分享的是如何去测试分发机制的文章,如果你想要自己去测试一番事件分发机制但又没有思路测试,或许这篇文章会对你有一些帮助。

事件分发常识

<li>事件流:用户从按下到松开屏幕之间所产生的所有事件组成称为一个事件流。</li>
<li>事件的基本传递方向Activity——>ViewGroup——>View。</li>
<li>用户在Activity产生的所有事件,系统首先调用<b>Activity</b>的dispatchTouchEvent方法进行分发。</li>
<li>dispatchTouchEvent: Activity和ViewGroup通过调用自身的该方法完成事件分发。返回布尔值。</li>
<li>onInterceptTouchEvent: ViewGroup分发逻辑上会调用这个方然来判断是否拦截事件。返回布尔值。</li>
<li>onTouchEvent: 事件的消费方法。返回布尔值。</li>
<li>View (例如:TextView)如果传递到该层,那么就不再进行事件分发,而是自己消费,作为事件传递的最终载体。</li><br />

方便测试,这些常识最好熟记。

提出相关问题

dispatchTouchEvent:事件分发方法
onInterceptTouchEvent:事件拦截方法
onTouchEvent:事件消费方法
以下不写方法名称,只写翻译的中文意思
<pre>
1.系统调用Activity的事件分发方法进行事件分发后,这个方法的返回值对于系统意味着什么?<pre>测试结果:这个返回值对于系统没有任何影响,无论返回什么值,系统对用户产生的r任何事件都会调用该方法进行分发</pre>2.ViewGroup的事件分发方法的返回值是否影响了Activity对该事件的进一步处理?<pre>测试结果:是!如果ViewGroup分发结果返回true,则Activity不处理,如果返回false,则处理,即Activity.onTouchEvent被调用。</pre>3.ViewGroup的事件拦截方法的返回值对于ViewGroup的事件分发方法是否有影响?<pre>测试结果:有影响,决定了是否继续分发到下一层还是自己消费事件。</pre>4.ViewGroup的事件拦截方法的返回值是否决定了ViewGroup的事件消费方法的执行?<pre>测试结果:是!</pre>5.ViewGroup的事件消费方法的返回值是否决定了ViewGroup的事件分发的返回值?<pre>测试结果:是!</pre>6.测试ViewGroup的事件拦截方法的返回值是否影响了其子类的事件分发方法的执行?<pre>测试结果:是!当ViewGroup的拦截方法返回false,则把事件传递到子类,即子类的事件分发方法被调用继续分发</pre>7.测试View的事件消费方法的返回值是否决定了View的事件分发方法的返回值?<pre>测试结果:是!</pre>8.View的事件分发方法的返回值是否影响了其父类的对该事件做进一步处理?<pre>是!如果view消费的情况返回false,那么ViewGroup会认为你没有处理ViewGroup会消费该事件,如果返回true,ViewGroup会认为你已经处理不需要再去处理消费</pre>
</pre>

上面的问题是从上到下的测试流程,请自行测试。

测试思路

1.创建一个MainActivity,复写分发和消费方法
2.创建一个MyViewGroup继承FrameLayout,复写分发方法、拦截以及消费方法。作为MainActivity的布局的根节点
3.创建一个MyView继承TextView使用在MyViewGroup中

例如


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e(TAG,"Activity开始分发事件--------------------");
        boolean result = super.dispatchTouchEvent(ev);
        // boolean result = false;
        // boolean result= true;
        Log.e(TAG,"Activity事件分发结果-----------------------"+result);
        return result;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e(TAG,"Activity处理事件--------------------");
        boolean result = super.onTouchEvent(event);
        // boolean result = false;
        // boolean result= true;
        Log.e(TAG,"Activity处理事件结果-----------------------"+result);
        return result;
    }

首先要明确的一点是,这些个方法内调用super.xxxEvent(ev)还是直接返回true和false有本质的区别,使用super.xxxEvent(ev)则是采用父类的分发策略(比如Activity、ViewGroup、View),即这些方法都有三种情况要进行测试,调用父类的分发策略或者直接返回true和false;其中还有一个值得测试的点是,onTouchEvent方法的父类默认消费策略的结果会受哪些因素影响(比如clickable="true/false"),还有一个onDispatchTouchEvent的父类分发策略会不会受setOnTouchListener的影响?

测试前,首先看下Activity的dispatchTouchEvent方法的分发策略

Activity{
    public boolean dispatchTouchEvent(MotionEvent ev) {
        /**if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }*/

        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }
}

Activity的分发逻辑很简单,getWindow().superDispatchTouchEvent(ev)最终会去调用ViewGroup的事件分发方法。而Activity又会根据ViewGroup的分发结果来做处理,如果分发结果为true,则不做任何处理直接返回true,如果分发结果为false,则调用onTouchEvent消费事件,并把消费结果返回。

总结

测试完你会发现其实ViewGroup的分发逻辑才是重点,经过上面的测试,下面就可以写出ViewGroup的基本分发逻辑:

ViewGroup{
    public void dispatchTouchEvent(MotionEvent ev){
        boolean consume = false;
        if(onInterceptTouchEvent(ev)){
            consume = onTouchEvent(ev);
        }else {
            consume = child.dispatchTouchEvent(ev);
        }
        return consume;
    }
}

不过要知其所以然,还是需要从源码具体分析。

总结两个一劳永逸的点:

<pre>
onTouchEvent:一个事件如果按默认的分发策略,必然会被消费,即可能被Activity/ViewGroup/View的onTouchEvent方法消费,这个方法值决定了本层的dispatchTouchEvent方法的返回值,而本层的dispatchTouchEvent的返回值又影响了父类的dispatchTouchEvent方法对事件是否需要进一步处理的行为。<br />

dispatchTouchEvent:
在一个事件流中:
如果该方法对这个事件的分发结果返回false,那么意味着后续的事件将不再分发到该层,即不再调用该层的dispatchTouchEvent方法。
如果该方法对这个事件的分发结果返回true,那么意味着后续的事件将继续分发到该层,即调用dispatchTouchEvent方法。

</pre>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,176评论 5 469
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,190评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,232评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,953评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,879评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,177评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,626评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,295评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,436评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,365评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,414评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,096评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,685评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,771评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,987评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,438评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,032评论 2 341

推荐阅读更多精彩内容