精华内容
下载资源
问答
  • 进而分析了大黄酸对中枢兴奋传递的作用,发现神经元在灌流大黄酸前后小波熵参数值变化显著。研究表明,小波熵能较全面地表征EPSP信号特征,比传统参数更具代表性,并能较灵敏地反映神经元兴奋性改变,
  • 为了研究αCaMKII在小鼠前脑过量表达对岛叶皮层兴奋性锥体细胞基本电生理特性和突触传递的影响,利用脑片膜片钳技术研究αCaMKII-F89G转基因小鼠岛叶皮层锥体细胞的基本电生理性质及突触传递。结果显示:野生型和α...
  • 2022届 高考 一轮复习 人教版强化练16 兴奋传导与传递的相关实验探究 作业.docx
  • 2022届 高考 一轮复习 人教版 热点题型七 兴奋传导与传递的相关实验探究题 教案.docx
  • 2022届 高考 一轮复习 人教版 强化练16 兴奋传导与传递的相关实验探究 课件 (16张).pptx
  • 2022届 高考 一轮复习 人教版 热点题型七 兴奋传导与传递的相关实验探究题 课件 (31张).pptx
  • JAVA 参数传递

    千次阅读 2013-11-21 13:51:01
    网络上有太多关于JAVA参数传递是传值还是传引用的讨论,其实大多是概念不清,混淆视听。从程序运行的角度来看,参数传递,只有传值,从不传递其它的东西。只不过值的内容有可能是数据,也有可能是一个内存地址。  ...

    网络上有太多关于JAVA参数传递是传值还是传引用的讨论,其实大多是概念不清,混淆视听。从程序运行的角度来看,参数传递,只有传值,从不传递其它的东西。只不过值的内容有可能是数据,也有可能是一个内存地址。

      Java中的数据类型有两大类,即基本类型(primitive types), 共有8种,包括int, short, long, byte, float, double, boolean, char,存在于栈(Stack)中。另一种暂称为对象类型,包括Integer, String, Double等相应基本数据类型的包装类,以及其他所有JAVA自带和用户自定义的类,这些类数据全部存在于堆中(Heap),如下图所示。

       对象类型的数据不同于基本类型的数据,我们所定义的对象变量并不是对象实例本身,而是对象的一个引用(reference)地址,该内存地址用来定位该对象实例在HEAP中的位置。对象实例本身和对象的引用分别保存在HEAP和STACK中,对象引用和对象实例之间的关系好比遥控器和电视机之间的关系,在房间走动的时候里,你只需拿着遥控器就可以控制电视机,而不必带着电视机。而且,即使没有电视机,遥控器也可以独立存在,也就是说你可以定义一个对象类型的变量,但是可以暂时不和一个对象实例关联。多个对象引用也可以指向同一个对象实例。

     

               Heap(堆)       Stack(栈)
     JVM中的功能            内存数据区                    内存指令区
     存储数据  对象实例  基本数据类型, 指令代码,常量,对象的引用地址

     

    下面我们来看看几个例子,您就会更加明白。

    例子1:

    public class Test {
    public static void changeValue(int i) {
    i=2;
    System.out.println("during test: i = " + i);
    }
    public static void main(String[] args) {
    int i = 1;
    System.out.println("Before test: i = " + i);
    changeValue(i);
    System.out.println("After test: i = " + i);
    }
    }
      运行结果:
    Before test: i = 1
    during test: i = 2
    After test: i = 1

    不难看出,虽然在 changeValue(int i)方法中改变了传进来的参数的值,但对这个参数源变量本身并没有影响。其内部原理是,main方法里的变量和changeValue方法的参数是两个不同的变量,以参数形式传递简单类型的变量时,实际上是将参数的值作了一个拷贝传进方法的,那么在方法里再怎么改变其值,其结果都是只改变了拷贝的值,而不是源值。

    例子2:

    public class Test {
    public static void test(StringBuffer str) {
    str.append(", World!");
    }
    public static void main(String[] args) {
    StringBuffer string = new StringBuffer("Hello");
    test(string);
    System.out.println(string);
    }
    }
      运行结果:
    Hello, World!

       在这个例子里,似乎变量string被“改变”了。但其实改变的并不是string变量本身,也就是说string保存的内存地址并没有被改变,改变的是它所指向的对象实例。内部原理是这样的,在main方法里定义了一个对象引用string,并且把它和一个对象实例关联new StringBuffer。方法调用的时候,string所保存的对象实例的内存地址传递给了test方法的对象引用参数str,这时就有两个对象引用变量指向同一个对象实例。这两个对象引用都可以对该对象实例进行操作,操作结果都有效,因此在test方法执行完之后,对象实例的内容已经被改变了,这个时候再通过main方法里的string引用去查看对象实例的内容,看到的就是改变之后的内容。

    例子3:

    public class Test {
    public static void test(String str) {
    str = "World";
    }
    public static void main(String[] args) {
    String string = "Hello";
    test(string);
    System.out.println(string);
    }
    }

    运行结果:

    Hello。

    这个结果和上面结果矛盾吗?一点也不矛盾。在这个例子中,参数传递过程和上个例子完全一样,但是在test方法里并不是对原来指向的对象实例进行操作,而是把str指向了另外一个对象实例,当然对原来的对象实例毫无影响。   


    总结:对于例1(基本数据类型),大家应该比较容易理解,因为Java调用方法的参数传递方式为“传值”,如method(O o),Java调用method(a),a传给o,即o的值等于a,但是明确一点,o与a是分割且独立的,可以理解o为a的一份拷贝,那么在方法method里面对o进行的任何操作,不会对a产生影响。就像电脑E盘下有一份word文档E:/B.doc,现在你要对B里面的内容进行修改,但是B.doc同样也是要使用的,那么就拷贝一份B.doc到F盘下名为F:/C.doc,那么B.doc和C.doc里面的内容完全相同,只是位置不同,B.doc在E盘下,C.doc在F盘下,他俩是相互分割且独立的,操作互不影响;

    对于例2和例3(对象/引用数据类型),其实和例1的原理是一样的,只是有点绕。这里要求大家回顾并理解Java中“对象”的概念和“如何操纵对象”,Java编程思想(第四版)第二章(一切都是对象)2.1节(用引用操纵对象)中第一段第一句话:“每种编程语言都有自己的操纵内存中元素的方式。”这句话貌似没有提到对象,但是提到了“内存中元素”,不管是基本数据类型还是对象/引用数据类型,都是数据,数据在Java虚拟机里都是分配在内存中(关于数据如何分配,请看《深入理解Java虚拟机》一书),所以这句话中”内存中元素“我们可以理解为”对象“。第二段第三句话:”尽管一切都看作对象,但操纵的标识符实际上是对象的一个“引用”(reference)。”从这两句话,我们可以这样理解:Java中的对象(数据)都保存在内存中,但是其实是通过直接操纵对象的一个引用来间接操纵对象。这里有个关键词“引用”,下面这张图片是Java编程思想(第四版)中对“引用”一词的解释,长篇大论。


    我先不理会书中的解释,给出自己形象的理解,可以把“引用”理解为电脑中的“快捷方式”,C盘深层目录下有一份word文档名为C:/Object/test/B.doc,但是我想用它,每次都要点开“我的电脑”-->C盘,然后再点到B.doc所在的目录,感觉狠繁琐,就把它生成一个快捷方式到桌面,右键快捷方式-->属性-->快捷方式栏目中有“目标”:C:/Object/test/B.doc这一项,这个目标就是说B.doc文件在这个快捷方式指向的位置C:/Object/test/B.doc,以后就可以直接操作快捷方式来间接操作B.doc了,是不是狠方便!

    上面对“对象”、“如何操纵对象”和“引用”做了一个详细的解释,现在我们言归正传,仍然以method(O o)为例,Java调用method(A),A为对象引用(快捷方式),对象实例(目标地址)为***,A传给o,o也是快捷方式,这里传的到底是什么?疑问我肯定地告诉你,是“值”,是对象实例的地址。那么对于例2,是不是就狠好理解了?是不是狠嗨皮!大笑但是这才是开始,例2和例3看着不是一样的么,为何结果不一样,你是不是又想哭了?快哭了注意例2中test方法体中操作对象的是这句:str.append(", World!");例3中的是:str = "World";结果不一样的关键就在于这两句话,现在我们应该都知道str是String对象“Hello”的快捷方式了吧!由“点”操作符的意义可知例2中str.append(", World!");中的append方法是String对象自身的方法,可以理解为word文档的“编辑”功能,可知是对str自身进行操作,也可以理解为对word文档内容进行修改;而例3中str = "World";的“=”操作符是赋值操作符,如果你看了《Java编程思想(第四版)》中第三章(操作符)3.4节(赋值)的内容,第一段第一句话是:“赋值使用操作符”=“。它的意思是‘取右边的值(即右值),把它复制给左边(即左值)’”这是对操作符的理解,但是这后面还有一段话,如下图:



    你是不是又觉得例3错了呢?纠结不抓狂,其实,上图对赋值操作符操纵对象的解释是完全正确的,而例3并没有违背以上解释,只是Java自带的特殊类String,关于String类的一系列特点和在Java中的特殊之处,在此就不赘述了,我只说结果,new操作符大家应该不陌生了吧,《Java编程思想(第四版)》中第二章(一切都是对象)2.2节(必须由你创建对象)第一段第一句:“一旦创建了一个引用,就希望它能与一个新的对象相关联。通常用new操作符来实现这一目的。new关键字的意思是‘给我一个新对象。’”这句话中“给我一个新对象”表明new操作符给引用一个新的内存地址值,而String str =“****”等同于String str = new String(“****”),例3中str = "World";意思就是说将新对象“World”的内存地址和str引用相关联,即例3中的快捷方式str指向新对象“World”的内存地址(目标位置),而例3中最后打印的是快捷方式string仍然指向原来的对象“Hello”,最后打印结果当然是“Hello”。到这里,我想例3的结果大家也认为是对的了吧!是不是又兴奋了一把大笑,终于把所有的问题都给Over了。

    总结之前的内容是拷贝的,总结之后是本菜鸟写的,其实看似简单,但是涵盖了很多对Java基础知识的理解!写得不好,勿喷~

    展开全文
  • 看圣火传递去了

    千次阅读 2008-05-08 17:02:00
    今天圣火在深圳传递,真是人多啊,简直就是people mountain people sea人们自发喊起来:中国,加油!当时的感觉是中国真的是站起来了,这种感觉真是令人兴奋

    今天圣火在深圳传递,真是人多啊,简直就是people mountain people sea

    人们自发喊起来:中国,加油!

    当时的感觉是中国真的是站起来了,这种感觉真是令人兴奋!

    展开全文
  • 客,传递处理某一行人指在过道交通单位点或断面的()的内通一地量是路某时间数量,行人货车客。计算机向计算结果标题写可下()形悬念抓住的撰的眼取以球A以采引导诱导号召式来受众式B式C式D式。...通过资料查阅有关...

    favicon_example.jpg摘要:

    通过资料查阅有关文献,计算机向计算结果息的估信取评以获方法是_。自行车B.客,传递处理某一行人指在过道交通单位点或断面的()的内通一地量是路某时间数量,行人货车客。计算机向计算结果标题写可下()形悬念抓住的撰的眼取以球A以采引导诱导号召式来受众式B式C式D式。...

    通过资料查阅有关文献,计算机向计算结果息的估信取评以获方法是_。

    胎心在宫减速出现缩开始时,用户迷走兴奋,、胎儿状则A带受、脐压好B况良,宫缩常后恢复正,短、恢复时间快。

    自行车B.客,传递处理某一行人指在过道交通单位点或断面的()的内通一地量是路某时间数量,行人货车客。通常糖皮质激骨质防性防治发性使用素诱疏松可预,钙剂钙剂物类药和阿化醇法骨双膦酸盐。人员则在的操作,进路建立后,而需某种解除由于原因时。不包二副下列做的计划前所内容内航次括在开航,规定按照,计总的总预计里程航线和预航行时间。

    54801916c21ccf673f103625997fbddc.png

    计算机向计算结果标题写可下()形悬念抓住的撰的眼取以球A以采引导诱导号召式来受众式B式C式D式。保证行车,天气恶劣排)做对(点安期间出重,因此。

    广告的特点有策划网络,用户C虚B指局性导性前性D全拟性A事。传递处理比较需求选择评价购买过程购买购后阶段决策的第诱发络消费者是网三个。通过向相重心重力阻分进方汽车力和行反的,计算机向计算结果坡度无关,个和将承受一,坡行阻力指汽车上上坡驶。用户子宫治疗观察宫切加放.肌全子全子癌伴内膜除术除术有转移的药物疗C瘤剔患者随访手术射治。形式多样化,传递处理包括播时广告告传的特点不网络、网络广空广。

    计算机向计算结果软件调查词解法名释。苯丙酮B.他莫腺癌子宫.甲.甲对乳、用户前癌、癌均内膜有治用的药物列腺疗作龙D是(酸诺。

    集疏其主要作用是客流,传递处理票、咨询供售、检等服为乘务客提,通道风亭,。

    计算机向计算结果病灶绒毛膜癌治疗子宫感染的主的是切除残存出血穿孔要目预防预防预防化疗手术缩短时间。

    用户D倍他米米松皮质泼尼作用最弱激素甲泼的糖地塞氢化尼龙是(松B松C松E抗炎可的。

    每天、传递处理卸早晨.装工人.加油、完毕换班后B后C水后,不必下列值班观看驾驶情况员可水尺,。统一指挥,。统一心(下在控制中指挥)的,条件下的行车组织集中调度方式控制,行车对列的到车在车站利用设备。集疏其主要作用是客流,传递处理票、咨询供售、检等服为乘务客提,通道风亭,。

    展开全文
  • ViewGroup和View的事件传递原理

    千次阅读 2015-11-08 20:56:22
    View和ViewGroup的事件传递机制 view和viewgroup的事件传递机制。很早就想好好改清楚里面的关系。终于花了一个星期的时间,一直研究,基本上可以解决我们常遇到问题。本文以例子和源码为主

    View和ViewGroup的事件传递机制

    view的事件传递一直是我一个软肋,以前我知道个大概,就是表面的意思是这样的,但是具体到这一些细节还是出了问题,所以,我花了较多时间看了下源码,并从其他的人的博客得到一些启发,但是还多博客都是一上来就是源码的,给人一种慢慢看完了不知道在说什么,只有等到自己梳理一遍,才完全知道。
    本文要说明view的事件传递机制,从源码入手,清晰说明MotionEvent在view和activity的中传递的过程,虽然源码较多,但是我采取一种主线下去的感觉:

    另外欢迎大家指出其中错误

    • TouchTarget类的简单说明

    • Activity和View之间的motionEvent的传递

    • ViewGroup的关于MotionEvent传递方法的介绍

    • View的关于MotionEvent传递方法的介绍

    • 总结

    • 感谢


    TouchTarget的介绍

    touchtarget是viewgroup的一个静态类,在这面我们贴下的它的源码

    private static final class TouchTarget {
            private static final int MAX_RECYCLED = 32;
            private static final Object sRecycleLock = new Object[0];
            private static TouchTarget sRecycleBin;
            private static int sRecycledCount;
    
            public static final int ALL_POINTER_IDS = -1; // all ones
    
            // The touched child view.
            public View child;
    
            // The combined bit mask of pointer ids for all pointers captured by the target.
            public int pointerIdBits;
    
            // The next target in the target list.
            public TouchTarget next;
    
            private TouchTarget() {
            }
    
            public static TouchTarget obtain(View child, int pointerIdBits) {
                final TouchTarget target;
                synchronized (sRecycleLock) {
                    if (sRecycleBin == null) {
                        target = new TouchTarget();
                    } else {
                        target = sRecycleBin;
                        sRecycleBin = target.next;
                         sRecycledCount--;
                        target.next = null;
                    }
                }
                target.child = child;
                target.pointerIdBits = pointerIdBits;
                return target;
            }
    
            public void recycle() {
                synchronized (sRecycleLock) {
                    if (sRecycledCount < MAX_RECYCLED) {
                        next = sRecycleBin;
                        sRecycleBin = this;
                        sRecycledCount += 1;
                    } else {
                        next = null;
                    }
                    child = null;
                }
            }
        }
    

    不难发现TouchTarget是一个链表结构的final类,其中sRecycleBin保存着当前的所有touchtarget的对象(static),另外next的中包含下一个信息。并且通过sRecycledCount来计数。
    接下来我们简单说下其中obtain()和recycle()的方法。
    obtain()

    target = sRecycleBin;
    sRecycleBin = target.next;
    sRecycledCount--;
    target.next = null;

    新生成的target 的中next指向以前的以前存在的对象,就是依次往回加的感觉,同时sRecycledCount是减一的。

    接下来就是recycle()的

    next = sRecycleBin;
    sRecycleBin = this;
    sRecycledCount += 1;

    就是把链表中最上面的去掉,也就是最新obtain()的那个给去掉。同样也是谁调用recycle()的这个对象在链表被去除了。但是不影响链表其他的对象,这点非常重要。
    TouchTarget类暂时说到这儿了。

    Activity和View之间的motionEvent的传递

    我们知道activity显示的view是通过window来显示,同样在事件的传递的过程中,activity的motionevent也是通过window去传递给view的,看下面的源码你就知道了
    activity中dispatchTouchEvent()

    1 public boolean dispatchTouchEvent(MotionEvent ev) {
    2        if (ev.getAction() == MotionEvent.ACTION_DOWN)  {
    3            onUserInteraction();
    4        }
    5        if (getWindow().superDispatchTouchEvent(ev)) {
    6            return true;
    7        }
    8        return onTouchEvent(ev);
    9    }

    注意第6行中getWindow().superDispatchTouchEvent(ev)这行代码的意思,给中getWindow即为phoneWindow这个类
    phoneWindow中的superDispatchTouchEvent的方法

    public boolean superDispatchTouchEvent(MotionEvent event) {  
            return mDecor.superDispatcTouchEvent(event);  
    }

    mDecor的其实就是activity的根view,这个时候也就将MotionEvent从activity传到了view中。
    从上面我们可以看出了,activity对MotionEvent的传递先给交给mDecor(ViewGroup)进行分发,如果分发不成功,则交给自己的自己的onTouch()方法。这个结论先记住。

    ViewGroup的关于MotionEvent传递

    首先在说传递之前,我给大家说明两个词的概念
    1 处理:MotionEvent交给它来处理,并不代表它能消费掉MotionEvent。
    2 消费:MotionEvent不仅交给它处理,同样的也消费了这个MotionEvent。

    明白上面两个词的概念后。我们先说明下,ViewGroup的关于MotionEvent传递的方法有些:
    1 dispatchTouchEvent
    2 onInterceptTouchEvent
    3 requestDisallowInterceptTouchEvent
    4 onTouchEvent
    借助一段伪代码先概括下的ViewGroup关于MotionEvent事件传递

    public boolean dispatchTouchEvent(MotionEvent event){
        boolean handle = false;
        if(!onInterceptTouchEvent(event) || requestDisallowInterceptTouchEvent(event)&& event.getActionCode != MotionEvent.ACTION_DOWN){
        handle = child.dispatchEvent();
        }
        if(!handle){
            handle = onTouchEvent();
        }
        return handle;
    }

    这点我们先验证一下:首先我们先定义一个NoDispatchTouchEventViewGroup和另一个TouchEventViewGroup的两个viewgroup
    NoDispatchTouchEventViewGroup的中的dispatchTouchEvent的方法如下dispatchTouchEvent中让直接返回false这里写代码片

    @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            Log.e("TAG", "NoDispatchTouchEvent   dispatchTouchEvent ");
            return false;
        }

    TouchEventViewGroup dispatchTouchEvent的方法我们不做处理,但是我们在onTouchEvent()中让他消费这个事件

     @Override
       public boolean onTouchEvent(MotionEvent event) {
            Log.e("TAG", "TouchEventViewGroup 的onTouchEvent");
            return true;
        }

    activity的layout文件如下,就是让TouchEventViewGroup里面放着NoDispatchTouchEventViewGroup

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.idreamo.rrtoyewx.rrtoyewx.view.TouchEventViewGroup
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <com.idreamo.rrtoyewx.rrtoyewx.view.NoDispatchTouchEventViewGroup
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    
            </com.idreamo.rrtoyewx.rrtoyewx.view.NoDispatchTouchEventViewGroup>
    
    
        </com.idreamo.rrtoyewx.rrtoyewx.view.TouchEventViewGroup>
    
    
    </RelativeLayout>

    这个时候打印的结果如下
    这里写图片描述
    可以看到运行了一次NoDispatchTouchEventViewGroup的中的dispathTouchEvent(),然后以后就直接交给了TouchEventViewGroup的onTouchEvent()的方法。这也就是上面所说的处理和消费,可以看到,NoDispatchTouchEventViewGroup处理过这个事件的中down事件(down 是一个系列事件的最开始),但是并没有消费掉,这也就是后来他接受不到这个系列事件后来的事件的原因。而这系列的处理过程是在viewgroup的dispatchTouchEvent()中实现。也就是意味着viewgroup的dispatchTouchEvent()决定了事件是否向下传递。
    正如上面的我们伪代码一样。但是此时我们改下上面这个代码。就是在NoDispatchTouchEventViewGroup的dispatchTouchEvent()的返回值改为true;打印的log的为
    这里写图片描述
    并不没有打印NoDispatchTouchEventViewGroup的ontouchevent()
    这也就意味了viewgroup的dispatchTouchEvent()的控制着自身的onTouchEvent()的处理过程,dispatchTouchEvent()不仅管控着如何处理这个事件(传递),同时也管控着如消费这个事件。
    到这里是不是觉得viewgroup的dispatchTouchEvent()方法很神奇,好的,正如所愿,接下来我们来看下dispatchTouchEvent()的源码:

       public boolean dispatchTouchEvent(MotionEvent ev) {
    1      if (mInputEventConsistencyVerifier != null) {
    2            mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
            }
    
            // If the event targets the accessibility focused view and this is it, start
            // normal event dispatch. Maybe a descendant is what will handle the click.
    3        if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
    4           ev.setTargetAccessibilityFocus(false);
            }
    
    5        boolean handled = false;
    6        if (onFilterTouchEventForSecurity(ev)) {
    7            final int action = ev.getAction();
    8            final int actionMasked = action & MotionEvent.ACTION_MASK;
    
                // Handle an initial down.
    9           if (actionMasked == MotionEvent.ACTION_DOWN) {
                    // Throw away all previous state when starting a new touch gesture.
                    // The framework may have dropped the up or cancel event for the previous gesture
                    // due to an app switch, ANR, or some other state change.
    10              cancelAndClearTouchTargets(ev);
    11               resetTouchState();
    12           }
    
                // Check for interception.
    13            final boolean intercepted;
    14            if (actionMasked == MotionEvent.ACTION_DOWN
                        || mFirstTouchTarget != null) {
    15               final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
    16                if (!disallowIntercept) {
    17                    intercepted = onInterceptTouchEvent(ev);
    18                    ev.setAction(action); // restore action in case it was changed
    19                } else {
    20                    intercepted = false;
    21                }
    22            } else {
                    // There are no touch targets and this action is not an initial down
                    // so this view group continues to intercept touches.
    23                intercepted = true;
    24            }
    
                // If intercepted, start normal event dispatch. Also if there is already
                // a view that is handling the gesture, do normal event dispatch.
    25            if (intercepted || mFirstTouchTarget != null) {
    26                ev.setTargetAccessibilityFocus(false);
    27           }
    
                // Check for cancelation.
    
    28            final boolean canceled = resetCancelNextUpFlag(this)
                        || actionMasked == MotionEvent.ACTION_CANCEL;
    
                // Update list of touch targets for pointer down, if needed.
    29            final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
    30            TouchTarget newTouchTarget = null;
    31            boolean alreadyDispatchedToNewTouchTarget = false;
    32           if (!canceled && !intercepted) {
    
                    // If the event is targeting accessiiblity focus we give it to the
                    // view that has accessibility focus and if it does not handle it
                    // we clear the flag and dispatch the event to all children as usual.
                    // We are looking up the accessibility focused host to avoid keeping
                    // state since these events are very rare.
    33               View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
                            ? findChildWithAccessibilityFocus() : null;
    
    34                if (actionMasked == MotionEvent.ACTION_DOWN
                            || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
                            || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
    35                    final int actionIndex = ev.getActionIndex(); // always 0 for down
    36                    final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
                                : TouchTarget.ALL_POINTER_IDS;
    
    37 removePointersFromTouchTargets(idBitsToAssign);
    
    38                    final int childrenCount = mChildrenCount;
    39                    if (newTouchTarget == null && childrenCount != 0) {
    40                        final float x = ev.getX(actionIndex);
    41                        final float y = ev.getY(actionIndex);
    
    42                       final ArrayList<View> preorderedList = buildOrderedChildList();
    43                        final boolean customOrder = preorderedList == null
                                    && isChildrenDrawingOrderEnabled();
    44                       final View[] children = mChildren;
    45                       for (int i = childrenCount - 1; i >= 0; i--) {
    46                            final int childIndex = customOrder
                                        ? getChildDrawingOrder(childrenCount, i) : i;
    47                            final View child = (preorderedList == null)
                                        ? children[childIndex] : preorderedList.get(childIndex);
    
                                // If there is a view that has accessibility focus we want it
                                // to get the event first and if not handled we will perform a
                                // normal dispatch. We may do a double iteration but this is
                                // safer given the timeframe.
    48                            if (childWithAccessibilityFocus != null) {
    49                               if (childWithAccessibilityFocus != child) {
    50                                    continue;
    51                                }
    52                                childWithAccessibilityFocus = null;
    53                                i = childrenCount - 1;
    54                            }
    
    55                            if (!canViewReceivePointerEvents(child)
                                        || !isTransformedTouchPointInView(x, y, child, null)) {
    56                                ev.setTargetAccessibilityFocus(false);
    57                                continue;
    58                            }
    
    59                            newTouchTarget = getTouchTarget(child);
    60                            if (newTouchTarget != null) {
                                    // Child is already receiving touch within its bounds.
                                    // Give it the new pointer in addition to the ones it is handling.
    61                                newTouchTarget.pointerIdBits |= idBitsToAssign;
    62                                break;
    63                            }
    
    64                            resetCancelNextUpFlag(child);
    65                            if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                                    // Child wants to receive touch within its bounds.
    66                                mLastTouchDownTime = ev.getDownTime();
    67                                if (preorderedList != null) {
                                        // childIndex points into presorted list, find original index
    68                                    for (int j = 0; j < childrenCount; j++) {
    69                                        if (children[childIndex] == mChildren[j]) {
    70                                            mLastTouchDownIndex = j;
    71                                            break;
    72                                        }
    73                                    }
    74                                } else {
    75                                    mLastTouchDownIndex = childIndex;
    76                                }
    77                                mLastTouchDownX = ev.getX();
    78                                mLastTouchDownY = ev.getY();
    79                                newTouchTarget = addTouchTarget(child, idBitsToAssign);
    80                                alreadyDispatchedToNewTouchTarget = true;
    81                                break;
    82                            }
    
                                // The accessibility focus didn't handle the event, so clear
                                // the flag and do a normal dispatch to all children.
    83                            ev.setTargetAccessibilityFocus(false);
    84                        }
    85                        if (preorderedList != null) preorderedList.clear();
    86                    }
    
    87                    if (newTouchTarget == null && mFirstTouchTarget != null) {
                            // Did not find a child to receive the event.
                            // Assign the pointer to the least recently added target.
    88                        newTouchTarget = mFirstTouchTarget;
    89                        while (newTouchTarget.next != null) {
    90                            newTouchTarget = newTouchTarget.next;
    91                        }
    92                        newTouchTarget.pointerIdBits |= idBitsToAssign;
    93                    }
    94                }
    95            }
    
                // Dispatch to touch targets.
    96            if (mFirstTouchTarget == null) {
                    // No touch targets so treat this as an ordinary view.
    97                handled = dispatchTransformedTouchEvent(ev, canceled, null,
    98                        TouchTarget.ALL_POINTER_IDS);
    99            } else {
                    // Dispatch to touch targets, excluding the new touch target if we already
                    // dispatched to it.  Cancel touch targets if necessary.
    100                TouchTarget predecessor = null;
    101                TouchTarget target = mFirstTouchTarget;
    102                while (target != null) {
    103                    final TouchTarget next = target.next;
    104                    if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
    105                        handled = true;
    106                    } else {
    107                        final boolean cancelChild = resetCancelNextUpFlag(target.child)
    108                                || intercepted;
    109                        if (dispatchTransformedTouchEvent(ev, cancelChild,
    110                                target.child, target.pointerIdBits)) {
    111                            handled = true;
    112                        }
    113                        if (cancelChild) {
    114                            if (predecessor == null) {
    115                                mFirstTouchTarget = next;
    116                            } else {
    117                                predecessor.next = next;
    118                            }
    119                            target.recycle();
    120                            target = next;
    121                            continue;
    122                        }
    123                    }
    124                    predecessor = target;
    125                    target = next;
    126                }
    127            }
    
                // Update list of touch targets for pointer up or cancel, if needed.
    128            if (canceled
                        || actionMasked == MotionEvent.ACTION_UP
                        || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
    129                resetTouchState();
    130            } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
    131                final int actionIndex = ev.getActionIndex();
    132                final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
    133                removePointersFromTouchTargets(idBitsToRemove);
    134            }
    135        }
    
    136        if (!handled && mInputEventConsistencyVerifier != null) {
    137            mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
    138        }
    139        return handled;
    140    }

    是不是后悔了,一开始的兴奋被这140多行代码彻底浇灭了。没事,其实我也不是很明白每一行的代码的意思。但是我采用这个最简单教大家来看,我们都知道一个系列的事件是由一个down事件和若干个move事件和一个up事件组成的,所以在这里我们就按照这个思路来上看上面的代码。

    先看down事件,过滤下上面的代码
    首先是9到12行

    if (actionMasked == MotionEvent.ACTION_DOWN) {  
        cancelAndClearTouchTargets(ev);
        resetTouchState();
       }

    cancelAndClearTouchTargets(ev)中有个clearTouchTargets()的方法,看一下,我们会发现其中调用recycle()的方法,正如我门上面所说的mFirstTouchTarget将会从sRecycleBin中移除,另外
    cancelAndClearTouchTargets的方法中同样将child也从sRecycleBin给移除了

    private void clearTouchTargets() {
            TouchTarget target = mFirstTouchTarget;
            if (target != null) {
                do {
                    TouchTarget next = target.next;
                    target.recycle();
                    target = next;
                } while (target != null);
                mFirstTouchTarget = null;
            }
        }

    resetTouchState()

     private void resetTouchState() {
       clearTouchTargets();
       resetCancelNextUpFlag(this);
       mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
       mNestedScrollAxes = SCROLL_AXIS_NONE;
     }

    这里将mGroupFlags给重置了。这点我们只需要关注着么多,总之9到12行的代码主要将viewgroup的在down 之前进行状态重置和初始化。
    接下来12到21行主要说明了拦截的处理,但是呢,我们是down 的事件所以进入if内部,但是此时呢我们应该知道mFirstTouchTarget = null的,进入先判断disallowIntercept()的这个值,这个值主要是通过FLAG_DISALLOW_INTERCEPT的这个标志来决定的,而这个标志是通过requestDisallowInterceptTouchEvent来决定的

     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    
            if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
                // We're already in this state, assume our ancestors are too
                return;
            }
    
            if (disallowIntercept) {
                mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
            } else {
                mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
            }
    
            // Pass it up to our parent
            if (mParent != null) {
                mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
            }
        }

    通过child调用getParent().requestDisallowInterceptTouchEvent的方法让这个标志位改变,并且将一致延续到最上层viewgroup。
    如果child要求这个事件,此时会让onInterceptTouchEvent的返回值实效,但是这个前提是motionevent的actionCode为down,或者mFirstTouchTarget!=null的时候,而mFirstTouchTarget!=null是在down事件传递下去才会有值(这一点下面可以知道)所以我们记住第一个结论,
    通过child调用getParent().requestDisallowInterceptTouchEvent()的可以屏蔽掉父亲的onInterceptTouchEvent拦截的返回值,但是如果需要在这个系列的事件都有效,则需要将这个系列的事件down传递到孩子,即父亲不拦截down事件的向下传递,当然父亲的onInterceptTouchEvent的这个默认返回值为false。

    public boolean onInterceptTouchEvent(MotionEvent ev) {
            return false;
        }
    

    好了 ,接下里我们先默认这个down事件不拦截向下分发接下来进入33到94行中代码,在进入判断之前,不仅时MotionEvent.ACTION_DOWN,还有split && actionMasked == MotionEvent.ACTION_POINTER_DOWN,前面是单指,后面是有的新的手指加入,在这我们先考虑MotionEvent.ACTION_DOWN的情况下。同时更多关于MotionEvent的知识可以看下我之前写的博客android MotionEvent的相关的类的介绍

    接下来进入for循环中对每一个孩子进行遍历,按照从后向前的顺序检查这个MotionEvent是不是在这个child上(canViewReceivePointerEvents()和isTransformedTouchPointInView()),并交给他去处理(dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)),接下来我们看下dispatchTransformedTouchEvent()部分的源码

           if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
                event.setAction(MotionEvent.ACTION_CANCEL);
                if (child == null) {
                    handled = super.dispatchTouchEvent(event);
                } else {
                    handled = child.dispatchTouchEvent(event);
                }
                event.setAction(oldAction);
                return handled;
            }

    故此时,将事件分发给了孩子的dispatchTouchEvent()中,完成了down的事件的分发。并且当child的dispatchTouchEvent()的返回值为true的时候,这个时候将mFirstTouchTarget给赋值了。

     newTouchTarget = addTouchTarget(child, idBitsToAssign);
     alreadyDispatchedToNewTouchTarget = true;

    看下addTouchTarget的源码,其中

        private TouchTarget addTouchTarget(View child, int pointerIdBits) {
            TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
            target.next = mFirstTouchTarget;
            mFirstTouchTarget = target;
            return target;
        }

    如果此时viewgroup不是mDecorView,则我们知道TouchTarget的sRecycleBin其实是有值的(static),所以到现在你是不是觉得TouchTarget的在事件传递过程中扮演是什么角色了,它其实就是记录着事件传递过程中成功消费这个事件的所有的view和他的父亲,mFirstTouchTarget最上面的那个TouchTarget对象记录着事件被消费的childview的信息,通过链表来联系。接下来在这段代码中还有87到94 ,这段代码时处理多指的代码,当然这里不做多分析。当然这里主要说明了down的事件被孩子dispatchTouchEvent()返回true的时候,那么如果孩子返回false呢?接下向下看96到98 ,我们可以看到mFirstTouchTarget= null的时候,即这个down事件没有被孩子dispatchTouchEvent()的返回true的时候。回去调用handled = dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);
    dispatchTransformedTouchEvent的源码我们也贴出来,我们看到此时去调用了view.dispatchToucEvent(),这里我简单说下view.dispatchTouchEvent()简单源码,首先判断这个控件有没有onTouchListener,如果是则直接return true 并且调用相应的回调方法,否则,则调用本身的onTouchEvent()的方法,所以这里我们是viewgroup默认是没有onTouchListener,所以这个时候会去调用onTouchEvent(),根据其中的返回值来说明是否被down事件是否被消费了。最后将handle给返回。
    好了,上面上基本将down的在viewgroup的dispatchTouchEvent()如何传递梳理一下,接下来我们看下move和up,其实move和up差不多的。
    move的时候,如果mFirstTouchTarget!=null,是可以进入到是否判断拦截的。
    mFirstTouchTarget!=null,如果不是不拦截的,直接来到106行,调用了while循环去遍历孩子,判断谁之前消费了他,紧接再叫他处理dispatchTransformedTouchEvent(event),但是如果拦截呢?此时有113—120代码,可以看出来此时mFirstTouchTarget=null了,但是,此时谁去处理这个事件呢?理论上是交给activity的onTouchEvent()去处理,但是如果在消费这个事件的父亲上面有的可能针对这个事件去消费的话,则会交它去消费的( 特殊情况下,需要手动实现,不做考虑)。这个系列的事件此后的事件都默认不会交给这个child去处理了。有种感觉就是你要做,就得从头到尾都处理好这件事,如果其中有个事件你没做好,对不起,以后你都没机会了,不管你前面处理多好多好。

    接下来我们来看个例子。例子1
    一方面来验证我们前面所说的,另一方面来加深我们对之前的理解。我们自定义两个view ,一个ViewGroup,和一个View,代码如下:
    TouchView extends View

     @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction()&MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchView dispatchTouchEvent ,actionCode : "+actionCode);
            return super.dispatchTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            int actionCode = event.getAction();
            Log.e("TAG","TouchView  onTouchEvent"+", actionCode :" +actionCode);
            return true;
        }

    TouchViewGroup extends ViewGroup

     @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction()& MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchViewGroup dispatchTouchEvent   ,actionCode"+actionCode);
            return super.dispatchTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int actionCode = event.getAction()&MotionEvent.ACTION_MASK;
            Log.e("TAG","TouchViewGroup  onTouchEvent"+", actionCode :" +actionCode);
            return true;
    
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction()&MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchViewGroup onInterceptTouchEvent  ,actionCode: "+actionCode);
            return super.onInterceptTouchEvent(ev);
        }

    另外我们在MainActivity重写了其中的onTouchEvent

    @Override
        public boolean onTouchEvent(MotionEvent event) {
            int actionCode = event.getAction() & MotionEvent.ACTION_MASK;
            Log.e("TAG","MainActivity onTouchEvent   actionCode :" + actionCode);
            return super.onTouchEvent(event);
        }

    最后再贴下布局文件

     <com.example.rrtoyewx.person.TouchViewGroup
            android:id="@+id/tv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/white">
            <com.example.rrtoyewx.person.TouchView
                android:layout_width="match_parent"
                android:layout_height="match_parent">
            </com.example.rrtoyewx.person.TouchView>
    </com.example.rrtoyewx.person.TouchViewGroup>

    这是最简单的事件传递机制,我们在最上层的TouchView的onTouchEvent(),返回值为true,成功消费这个系列的事件。接下来我们log的打印的情况
    这里写图片描述
    可以看到,正如我们上面分析的一样的,当事件传递过来的时候,整体传递的过程为 TouchViewGroup.dispatchTouchEvent—->TouchViewGroup.onInterceptTouchEvent——>TouchView.dispatchTouchEvent—>TouchView.onTouchEvent.这也是最简单的事件传递。
    接下来我们就来修改下代码
    例子2 第一,我们在TouchViewGroup的onInterceptTouchEvent的返回值改为true;因为默认是false的,修改如下

    @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction()&MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchViewGroup onInterceptTouchEvent  ,actionCode: "+actionCode);
            return true;
        }

    此时应该正如我们上面所分析的一样,最终会交给了activity的onTouchEvent(),因为down的时候,把事件交给上面的view的处理时,TouchView没有接受到事件,就交给了TouchViewGroup,TouchViewGroup虽然处理了事件,但是并没有消费事件,所以TouchViewGroup的中mFirstTouchTarget并没有赋值。看下log是不是正如我们所说的
    这里写图片描述
    看了log 确实正如我们所说的,
    例子3,前面这两个似乎都挺容易理解的,接下来我们慢慢加深点,看大家能不能理解了,我们在TouchViewGroup的onInterceptTouchEvent的方法中,对down事件不进行拦截,我们对第一个move事件也不拦截,但是呢,我们对之后的事件开始拦截。代码修改如下:

    public boolean onInterceptTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction()&MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchViewGroup onInterceptTouchEvent  ,actionCode: "+actionCode);
            switch (actionCode){
                case MotionEvent.ACTION_DOWN:
                    return false;
                case MotionEvent.ACTION_MOVE:
                    if(mFirst){
                        mFirst = false;
                        return false;
                    }else{
                        return true;
                    }
                default:
                    mFirst = true;
                    return true;
            }
        }

    在看log之前,我们先分析下,down事件是可以传递下去,而且被消费了,mFirstTouchTarget被赋值了,此时当一个move事件来,也是可以被消费了,但是第二个move事件的时候,在判断是否拦截了,这个时候这个时间就没办了消费了,并且从之前的代码说明了此时mFirstTouchTarget = null;所以接下来事件都不会交到里面的那个TouchView了,全部会交给谁上次消费了这个事件,但是它的上次层的TouchViewGroup依然可以处理到这个事件,不像例子2,不会直接交给了activity里面,这点尤为重要
    这里写图片描述
    似乎log正如我们上面所分析的,第一个down事件成功被消费后,第二个事件来了似乎和我们上面所说的不太一样,并且你发现此时的actioncode变成3,也就意味着这是一个cancle的事件,其实这点我也没找到相应的转化代码,但是我的理解的是,viewgroup的里面的部分源码

    final boolean cancelChild = resetCancelNextUpFlag(target.child)
                                    || intercepted;
                            if (dispatchTransformedTouchEvent(ev, cancelChild,
                                    target.child, target.pointerIdBits)) {
                                handled = true;
                            }
                            if (cancelChild) {
                            }

    可以看到先交给他去处理,接下来拦截,所以这个事件是无效。希望懂的童鞋的能在下面的留言给我答案。我真的很想知道了。。。。
    但是这个无关大碍。接下来的log证实我们上面所说的,以后的事件他都会交给TouchViewGroup(TouchView的上面的view)的去处理,尽管它并没有消费掉,因为此时TouchViewGroup的mFirstTouchTarget==null,但是TouchViewGroup他上层的mFirstTouchTarget是有值的,并指向TouchViewGroup的。所以每次都会传到这儿的,不会像例子2种所有的viewGroup的mFirstTouchTarget都是==null的。这点希望大家慢慢体会下。
    这个时候,我们就可以做些事情了,比如TouchViewGroup拦截了事件,可以针对其中的某一些事件做些消费。代码实现也很简单。只需要我们我TouchViewGroup里面的onTouchEvent()做响应处理就可以了。
    例子4 ,我们似乎忘了一个requestDisallowInterceptTouchEvent方法了。接下来我们再改下代码
    TouchViewGroup的代码

     public boolean dispatchTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction()& MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchViewGroup dispatchTouchEvent   ,actionCode"+actionCode);
            switch (actionCode){
                case MotionEvent.ACTION_DOWN:
                    break;
                case MotionEvent.ACTION_MOVE:
                    requestDisallowInterceptTouchEvent(true);
                    break;
            }
            return super.dispatchTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int actionCode = event.getAction()&MotionEvent.ACTION_MASK;
            Log.e("TAG","TouchViewGroup  onTouchEvent"+", actionCode :" +actionCode);
            return super.onTouchEvent(event);
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction()&MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchViewGroup onInterceptTouchEvent  ,actionCode: "+actionCode);
            switch (actionCode){
                case MotionEvent.ACTION_DOWN:
                    return true;
                case MotionEvent.ACTION_MOVE:
                    return true;
                default:
                    return true;
            }
        }

    大家可以猜下log的打印情况(其实这是一种拦截的错误的写法),至于为什么会出现下面的log,我上面已经说出来,
    这里写图片描述
    例子5 ,正确的写法
    TouchViewGroup的代码

    public boolean dispatchTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction()& MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchViewGroup dispatchTouchEvent   ,actionCode"+actionCode);
            switch (actionCode){
                case MotionEvent.ACTION_DOWN:
                    break;
                case MotionEvent.ACTION_MOVE:
                    requestDisallowInterceptTouchEvent(true);
                    break;
            }
            return super.dispatchTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int actionCode = event.getAction()&MotionEvent.ACTION_MASK;
            Log.e("TAG","TouchViewGroup  onTouchEvent"+", actionCode :" +actionCode);
            return super.onTouchEvent(event);
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction()&MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchViewGroup onInterceptTouchEvent  ,actionCode: "+actionCode);
            switch (actionCode){
                case MotionEvent.ACTION_DOWN:
                    return false;
                case MotionEvent.ACTION_MOVE:
                    return true;
                default:
                    return true;
            }
        }

    我上面说了,要想用requestDisallowInterceptTouchEvent的有效。必须在TouchViewGroup的不拦截down事件。我们看下log
    这里写图片描述
    成功的反拦截了。
    例子6 ,其实这是我以前犯了一错误,其实那样是拦截不到,我贴下代码,大家可以看下,如果你看懂了,那么基本上ViewGroup的事件传递基本上都看懂了。
    TouchViewGroup的代码

    public boolean dispatchTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction()& MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchViewGroup dispatchTouchEvent   ,actionCode"+actionCode);
    
            return super.dispatchTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int actionCode = event.getAction()&MotionEvent.ACTION_MASK;
            Log.e("TAG","TouchViewGroup  onTouchEvent"+", actionCode :" +actionCode);
            return super.onTouchEvent(event);
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction()&MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchViewGroup onInterceptTouchEvent  ,actionCode: "+actionCode);
            switch (actionCode){
                case MotionEvent.ACTION_DOWN:
                    return false;
                case MotionEvent.ACTION_MOVE:
                    return true;
                default:
                    return true;
            }
        }

    什么都没做,就是拦截move事件
    接下来就是TouchView的代码

    @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction() & MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchView dispatchTouchEvent ,actionCode : " + actionCode);
            switch (actionCode) {
                case MotionEvent.ACTION_DOWN:
                    break;
                case MotionEvent.ACTION_MOVE:
                    getParent().requestDisallowInterceptTouchEvent(true);
                    break;
            }
            return super.dispatchTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            int actionCode = event.getAction();
            Log.e("TAG", "TouchView  onTouchEvent" + ", actionCode :" + actionCode);
    
            return true;
        }

    或者是这样

    @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction() & MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchView dispatchTouchEvent ,actionCode : " + actionCode);
            return super.dispatchTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            int actionCode = event.getAction();
            Log.e("TAG", "TouchView  onTouchEvent" + ", actionCode :" + actionCode);
            switch (actionCode) {
                case MotionEvent.ACTION_DOWN:
                    break;
                case MotionEvent.ACTION_MOVE:
                    getParent().requestDisallowInterceptTouchEvent(true);
                    break;
            }
            return true;
        }

    打印的结果都是这样子的
    这里写图片描述
    结果却是没拦截到。是不是觉得很奇怪,不急,我在改点东西,我让第一move事件不拦截,其他都拦截,就像我们上面写的代码一样
    TouchViewGroup的代码

      public boolean onInterceptTouchEvent(MotionEvent ev) {
            int actionCode = ev.getAction()&MotionEvent.ACTION_MASK;
            Log.e("TAG", "TouchViewGroup onInterceptTouchEvent  ,actionCode: "+actionCode);
            switch (actionCode){
                case MotionEvent.ACTION_DOWN:
                    return false;
                case MotionEvent.ACTION_MOVE:
                    if(mFirst){
                        mFirst = false;
                        return false;
                    }else{
                        return true;
                    }
                default:
                    mFirst = true;
                    return true;
            }
        }

    此时log,你会惊讶的,因为此时居然可以反拦截了这里写图片描述
    到这儿,似乎你有点纳闷了,为什么跳过了一个down的事件的就可以拦截了,其实是顺序的问题。你要想想,执行的顺序是什么?先执行TouchViewGroup dispatchTouchEvent ,这个时候已经在判断FLAG_DISALLOW_INTERCEPT的标志位,并没有改变,直到你在TouchView的dispatchTouchEvent去改变,这个时候,已经是然并卵了。最好就是在TouchView的down的时候就开始反拦截。然后根据需求来在决定在以后需不需要不反拦截,而不是一上来不反拦截,而是到了该拦截再去拦截,这个时候已经迟了。

    ok,说了这么多的dispatchTouchEvent(),你似乎还想说onTouchEvent()还没说,其实呢。ViewGroup中的onTouchEvent()跟view的onTouchEvent()是一样,我们放在下面来说。

    View中MotionEvent的介绍

    view的就两个方法比较重要,其实view事件传递是比较简单的。
    dispatchTouchEvent()
    onTouchEvent()
    首先看下dispatchTouchEvent()的源码,我们直接跳重点看吧

     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;
                }
            }

    dispatchTouchEvent的其他的代码,都是无关紧要的。直接看这段,可以看到先判断了是否存在了touchlistener,如果有,则执行了
    mOnTouchListener的ontouch的方法。根据返回值,决定需不要执行onTouchEvent(event),也就是说OnTouchListener的ontouch的优先级高于onTouchEvent()的方法。是不是觉得view的dispatchTouchEvent特别简单。其实这很正常,想想view是负责处理和消费事件的,所以它的dispatchTouchEvent出了分发给自己,还能怎么办?你可能会问这是不是意味着onTouchEvent()会很难,实际上它的onTouchEvent()还真不难.不信接着看下来
    onTouchEvent()核心代码

     if (((viewFlags & CLICKABLE) == CLICKABLE ||
                    (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
                    (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
                switch (action) {
                    case MotionEvent.ACTION_UP:
                        boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
                        if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
                            // take focus if we don't have it already and we should in
                            // touch mode.
                            boolean focusTaken = false;
                            if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
                                focusTaken = requestFocus();
                            }
    
                            if (prepressed) {
                                // The button is being released before we actually
                                // showed it as pressed.  Make it show the pressed
                                // state now (before scheduling the click) to ensure
                                // the user sees it.
                                setPressed(true, x, y);
                           }
    
                            if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
                                // This is a tap, so remove the longpress check
                                removeLongPressCallback();
    
                                // Only perform take click actions if we were in the pressed state
                                if (!focusTaken) {
                                    // Use a Runnable and post this rather than calling
                                    // performClick directly. This lets other visual state
                                    // of the view update before click actions start.
                                    if (mPerformClick == null) {
                                        mPerformClick = new PerformClick();
                                    }
                                    if (!post(mPerformClick)) {
                                        performClick();
                                    }
                                }
                            }
    
                            if (mUnsetPressedState == null) {
                                mUnsetPressedState = new UnsetPressedState();
                            }
    
                            if (prepressed) {
                                postDelayed(mUnsetPressedState,
                                        ViewConfiguration.getPressedStateDuration());
                            } else if (!post(mUnsetPressedState)) {
                                // If the post failed, unpress right now
                                mUnsetPressedState.run();
                            }
    
                            removeTapCallback();
                        }
                        mIgnoreNextUpEvent = false;
                        break;
    
                    case MotionEvent.ACTION_DOWN:
                        mHasPerformedLongPress = false;
    
                        if (performButtonActionOnTouchDown(event)) {
                            break;
                        }
    
                        // Walk up the hierarchy to determine if we're inside a scrolling container.
                        boolean isInScrollingContainer = isInScrollingContainer();
    
                        // For views inside a scrolling container, delay the pressed feedback for
                        // a short period in case this is a scroll.
                        if (isInScrollingContainer) {
                            mPrivateFlags |= PFLAG_PREPRESSED;
                            if (mPendingCheckForTap == null) {
                                mPendingCheckForTap = new CheckForTap();
                            }
                            mPendingCheckForTap.x = event.getX();
                            mPendingCheckForTap.y = event.getY();
                            postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                        } else {
                            // Not inside a scrolling container, so show the feedback right away
                            setPressed(true, x, y);
                            checkForLongClick(0);
                        }
                        break;
    
                    case MotionEvent.ACTION_CANCEL:
                        setPressed(false);
                        removeTapCallback();
                        removeLongPressCallback();
                        mInContextButtonPress = false;
                        mHasPerformedLongPress = false;
                        mIgnoreNextUpEvent = false;
                        break;
    
                    case MotionEvent.ACTION_MOVE:
                        drawableHotspotChanged(x, y);
    
                        // Be lenient about moving outside of buttons
                        if (!pointInView(x, y, mTouchSlop)) {
                            // Outside button
                            removeTapCallback();
                            if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
                                // Remove any future long press/tap checks
                                removeLongPressCallback();
    
                                setPressed(false);
                            }
                        }
                        break;
                }
    
                return true;
            }

    看了上面的代码是不是觉得很操蛋,但是你注意到了最后return true。这个是不是很有趣,我不管里面具体实现是什么,只要你进入了if里面就时代表你处理并消费了事件。好的,我们看下进入if的条件viewFlags & CLICKABLE) == CLICKABLE ||
    (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
    (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE,我翻译直白的点,其实就是判断这个view时可点击的,可长按的,还有一个我也不知道,好的,记住前两个就行了。换句话说,只要这个view是可点击的,可长按的,这两个属性怎么设置的呢?第一种,当你给他她们设置了setOnClickListener,或者setOnLongClickListener(),这个时候已经设置可点击了或者可长按的
    view中 setOnLongClickListener的源码。

    public void setOnLongClickListener(@Nullable OnLongClickListener l) {
            if (!isLongClickable()) {
                setLongClickable(true);
            }
            getListenerInfo().mOnLongClickListener = l;
        }

    从设置监听我们就可以看到第二种方法setLongClickable()和setClickable();第三种方法,xml android:clickable="true"
    android:longClickable="true"

    默认的Clickable或者LongClickable为true还是有一些控件的,比如button,checkbox等。
    好了上面已经说明了如何进入这个if语句中,也就是如何让view去消费这个事件,关于if的里面的代码逻辑,其实就是在up的时候判断是否可以触发点击事件,在move的时候是否能触发长按事件。
    最后说一点,判断一个view能否消费事件仅仅只是判断是否可点击或者可长按的,与是不是enable没关系。

    总结

    1 viewgroup的dispatchTouchEvent()的伪代码如下

    public boolean dispatchTouchEvent(MotionEvent event){
        boolean handle = false;
        if(!onInterceptTouchEvent(event) || requestDisallowInterceptTouchEvent(event)&& event.getActionCode != MotionEvent.ACTION_DOWN){
        handle = child.dispatchEvent();
        }
        if(!handle){
            handle = onTouchEvent();
        }
        return handle;
    }

    2 viewgroup一开始就拦截向child传递的motionEvent,如果他onTouchEvent()没有消费掉事件,则这个系列以后的事件都没办法传递到它这儿
    3 viewgroup一开始不拦截向child传递的motionEvent,并且child成功的消费了motionEvent,则当拦截以后,这个系列的事件以后的事件都能能传到viewgroup这个,尽管它并没有消费掉这个事件
    4 如果child想反拦截,那么首先第一必须得down事件传递下去并消费掉,使得接下来的事件能够传递下去。
    5 反拦截的顺序一定要注意先后,详情请好好看看viewgroup的例子6,
    6 view中onTouchListener的执行顺行要先于onClickListener和onLongChilckListener,并且onTouchListener中onTouch()返回值决定需不需要执行onClickListener和onLongChilckListener。
    7 view是否消费事件,仅仅由自己的clickable属性和LongClickable的属性有关。

    展开全文
  • 艺术,传递情感

    2012-05-10 14:18:36
    我是个理工男,虽然没有迂腐到不懂任何风月的程度,但非常缺少艺术的细胞,从来就不明白,为什么哪些潦草的画作...绘画和照片能精确的传递光影,音乐能精确的传递韵律,那么这些形式的作品,如何向受众传递作者的情感?
  • 两栖动物交感神经节表现出多种突触后电位,包括快兴奋性突触后电位(fEPSP),慢抑制性突触后电位(sIPSP),慢兴奋性突触后电位(sEPSP),晚期慢兴奋性突触后电位(lsEPSP),同时还表现多种突触塑性,说明该神经...
  • 目的:研究依托咪酯对大鼠腹外侧视前区神经元γ-氨基丁酸能传递的...结论:依托咪酯可作用于突触前及突触后γ-氨基丁酸受体而抑制对腹外侧视前区神经元的γ-氨基丁酸能传递,这一作用可能使其处于兴奋状态,进而抑制结节
  • Android面试题-兴奋了有木有

    千次阅读 2012-08-14 17:37:46
    Android面试题-兴奋了有木有 什么是Activity? 请描述一下Activity生命周期。 答:创建 onCreate - 启动onStart – 开始 onResume – 暂停 onPause – 结束 onStop –销毁onDestroy 两个Activity之间跳转时必然...
  • 我们系统地研究了通过不可靠的突触,由随机的兴奋性和抑制性输入峰值驱动的单个霍奇金-赫克斯利神经元的随机动力学。 基于均值理论,提出了一种基于不可靠突触的新型内在神经元噪声调节机制。 我们的仿真结果表明,...
  • 记录了离体海马脑片 CA1区锥体神经 元 PS,发现损伤侧和非损伤侧 PS的 Renyi信息参数值差异显著,进而分析了神经元灌流大黄酸后损伤侧 PS的 Renyi信息参数值的变化,研究大黄酸对神经元的超兴奋性和突触传递的作用 ...
  • 神经元-突触传递

    2012-07-02 11:02:15
    如果这种作用足够大时,即可引起突触后神经元发生兴奋或抑制反应。  单胺类递质的神经元的突触传递另有一种方式。这类神经元的轴突末梢有许多分支,在分支上有大量的结节状曲张体。曲张体内含有大量的小泡,是递...
  • BP神经网络理论推导一、...轴突能将神经元的兴奋传递给其连接的神经元,而树突能够接收其他神经元传递过来的兴奋。神经元细胞根据接收到的兴奋决定是否将兴奋传递给下一个神经元细胞。神经元模型将神经元细胞抽象为数学
  • 目的:研究多巴胺D1受体的选择性激动剂SKF38393对大鼠伏隔核棘状神经元自发兴奋性突触后电流的影响。方法:大鼠伏隔核切片,全细胞...结论:D1受体激动剂对大鼠伏隔核棘状神经元谷氨酸受体介导的突触传递起双向的调节作用。
  • 6月4号,对长沙人来说是很兴奋的一天,因为奥运火炬今天会在长沙传递。我们学校5点半就准时从学校的北门出发,走十五里到咸嘉新村去,那里是我们今天的目的地。长长的队伍出发了,从头看不到尾,每个人都穿着白色的T...
  • 通信无非就是互发数据,首选Socket技术,通过TCP协议建立长连接,一般是以字节数组的形式传递数据,也就是说,无论传递什么东东,都先拆成字节数组。 既然是面向对象编程,发送的数据要用实体类封装,同时配合List ...
  • BP 神经网络原理及应用 人工神经网络简介 1.1 生物神经元模型 神经系统的基本构造...和一些向外伸出的其它较短分支树突组成 轴突的功能是将本神经元的输出信号兴奋传递给别的神经元 其末端的许多神经末梢使得兴奋可以同
  • 二、PHP自定义传递参数: 当我调通微信支付时,看见支付那个页面时候很兴奋,但是兴奋之后我发现有问题了,始终是一分钱(其实对于用户来说很爽O(∩_∩)O,但是客户会杀了我的T_T)。所以我就得改啊。 可是我...
  • 经过几番周折,终于结合网上和自己的理解,通过参数字段方法传递了我要显示的值了!实在是很高兴,因为这是进步,还要努力,下面把这段自己写的代码奉献给大家分享: using System;using System.Data;using ...
  • 谷歌年度I/O开发者大会传递出一个明显的信号,即谷歌正试图把Android进化成为用户和开发者的体验,而不仅仅是一个平台。 在本届全球开发者大会中,谷歌展示了设计精美的设备Nexus 7和Nexus Q,向我们表明Android...
  • 神经元是一种可电兴奋的细胞,它通过电信号和化学信号接收、处理和传输信息。 神经元之间的通讯是通过控制调节膜电位的离子通道来建立的。 最后一个充当信号。 在施加幅度相当大的电流脉冲后,可兴奋细胞的膜电位在...
  • Nutch数据在各模块间的传递

    千次阅读 2012-06-10 16:15:12
    ok,我知道很多人都是看code比看document更兴奋,很不幸,我也是其中一员。 . 排序 比如你有一批URL,存放在文本文件c:/tmp/tmpin/urllist.txt中,一行一个 http://www.sohu.com http://www.163.com ...
  • 转自:... ...Struts2向对象传递数据及Struts2中怎么获取request,response,session详解  struts2 面向对象传递数据  如果你以前用过Struts1,那你一定知道ActionForm,它在struts1框架中
  • 为什么Java小伙对Node.js和JavaScript 如此兴奋? – David Herron , 软件工程师和作家,热衷于Node.js 以及清洁能源技术。Node.js WEB 开发网站的作者。https://sourcerer.io/robogeek 在Sun Microsystems 公司...
  • 还记得02年11月30日,是第1次献血的日子,难以忘记那时紧张而忐忑不安的心情和献血后的兴奋,马上就打IC电话回家给爸妈说我献血了!还记得妈妈赞的话一句没说,就骂我不珍惜身体,念叨着要多吃鸡蛋和肉补充营养……...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,046
精华内容 7,218
关键字:

兴奋传递