Android 事件分发机制

前言

我们都知道给一个控件注册点击事件是只需要setOnClickListener,传入一个实现了onClick方法的匿名内部类,注册触摸事件只需要setOnTouchListener,传入一个实现了onTouch方法的匿名内部类,但是你会发现onTouch不同于onClick的一点是它是具有返回值的,这个返回值有什么用呢,onTouch和onClick方法谁先被调用呢?他们都是在那个函数中被调用的呢?下面我们就来看一看!

基础

 

我们可以看到onTouch是先于onClick被调

用的,那么我们在手都抛一个异常来看一下他的函数调用栈

这个只是截取了一部分,我们只看到追溯到Activity即可,所以对于onTouch方法,它是这样被调用的 … … -> Activity.dispatchTouchEvent -> PhoneWindow.superDispatchTouchEvent -> DecorView.superDisparchTouchEvent -> ViewGroup.dispatchTouchEvent – > ViewGroup.dispatchTransformedTouchEvent -> View.dispatchTouchEvent 那我们就可以按照这个顺序来看一看正常情况下的事件流的流向和相关函数代码

同时我们也可以看出对Touch事件它是由Activty->ViewGroup->View三层结构由外到内,Android5.0后代码变得更复杂了,但是原理没有变,我们就看一看便于理解的老代码

在开始之前为了第一次接触的人便于理解,我就简单的把情况设置为这个Activity中只有一个Layout,Layout中只有一个Button,所以只有一个Activty,一个ViewGroup,一个View,但是你要明白的是在安卓里ViewGroup也是一个View,View拥有dispatch方法,而ViewGroup作为它的子类重写了该方法,在后面提到时你要区分它调用的是作为Layout(ViewGroup)的dispatch方法,还是Layout作为一个View的dispatch方法!!!另外你还要区分ViewGroup是View的子类,Button是ViewGroup的子view

继续阅读

微北洋-代码读后感(1)

如何绘制一条优秀的GPA曲线

(1)准备工作

在布局文件中我们发现了很多自定义View,找到GPA曲线的自定义GpaLineChartView

 

在APP中对应红线部分

 

下面是该View的布局说明,除去四周的padding,实际的画布大小为图中红线部分

对应APP中位置,实际设置中Left和Right padding均为0dp 继续阅读

数据结构-树(4)

上一章我们讲解了二叉树的创建和遍历,这一章就可以放开手脚大干一场了

线索二叉树

什么是线索二叉树:二叉链表中有2n个指针域,其中n+1个指针域存放的都是NULL,我们要把这些指针域利用起来,存放节点的前驱和后继。

用处:对二叉树遍历的过程实质上是对一个非线性结构进行线性化的操作,以二叉链表为存储结构时,结点的左右孩子可以直接找到,但不能直接找到结点的前驱和后继,而结点的前驱和后继只有在遍历二叉树的过程中才能得到,效率低下。在后面的中序查找和平衡二叉树中会非常有用。

结点结构

我们在原有节点的基础上又添加了LeftThread和RightThread两个标志位,因为我们需要区分每个节点的指针域内的指针究竟是指向它的孩子还是指向它的前驱或者后继。虽然增加了空间,但是减少了时间

LeftThread=0, LeftChild指向左孩子
LeftThread=1, LeftChild指向前驱
RightThread=0, RightChild指向右孩子
RightThread=1, RightChild指向后继

 

二叉树线索化

不同的遍历顺序,每个节点的前驱和后继自然也不一样

中序线索化二叉树

后继:结点标志为1时,其右指针为其后继;结点标志为0时,其右子树最左下结点为其后继。
前驱:结点标志为1时,其左指针为其前驱;结点标志为0时,其左子树最右下结点为其前驱。

我们根据下图来看一下上面代码的思路,中序线索化和中序遍历思路一样一样的,我们其实只需要修改中序遍历中的visit也就是访问函数即可,具体来看一下 继续阅读

数据结构-树(3)

二叉树的存储结构

第一篇博客里已经大概讲述了一下连续存储和顺序存储,下面我们再来具体看一下

链式存储

对于二叉树来说,每个节点的度都小于等于二,所以我们在定义节点时并不会造成大量的浪费,我们完全可以用链式结构来存储,同时类比单链表和双向链表,我们可以添加一个指针域来指向它的父节点

 

同样类比静态链表,三叉链表也有静态形式

 

连续存储

第一篇博客里讲到了如果要连续存储一棵树需要把它转换成完全二叉树,可以是从普通二叉树转化而来,也可以是一颗普通的树通过孩子兄弟表示法转化成的二叉树转化而来 继续阅读

数据结构-树(2)

树的存储

树中的每个节点之间都有着不同的关系,如双亲,孩子,兄弟等等,我们在存储一棵树的同时也要把他们之间的关系存储进去。下面我们就要介绍四种表示方法:孩子表示法  双亲表示法   双亲孩子表示法   孩子兄弟表示法

孩子表示法

顾名思义,孩子表示法就是在每一个节点中都包含了它的孩子的信息。比如孩子的地址或者下标。

对于所有的树来说,我们都可以用链式存储,但是我们在定义节点的时候会遇到一个问题,这个节点中我们究竟需要几个指针域?一种方法就是,遍历整棵树,求出最大的度,(不知道度的看上一章),在定义节点的时候定义同样数量的的指针域,但是很明显这样会造成大量浪费。

 

同样我们可以用静态链表,也就是数组的方式来表示,但同样也会造成大量浪费,那有没有什么好的办法呢?当然有,有这么一种看着就很牛逼的方法,数组和链表相结合,虽然也有浪费,但是其实浪费是很少的

数据结构=个体+个体关系,我们要对给定的数据进行存储,其实就是存储这两部分,个体和他们之间的关系,我们把每一个个体存放到数组中,同时又对每一个个体添加了一个链表,来存放它和其它个体的关系,也就是存放它的孩子的下标。

继续阅读

数据结构-链表(2)

约瑟夫问题

n 个人围成一个圆圈,首先第1个人从1开始一个人一个人顺时针报数, 报到第m个人,令其出列。然后再从下一个人开始,从1顺时针报数,报到第m个人,再令其出列,…,如此下去, 直到圆圈中只剩一个人为止。此人即为优胜者。
例如 n = 8 m = 3

对于这个问题我们用完全可以用循环队列来解决,但是这里我们为了加深一下对链表的操作,我们来用单循环链表来解决。很好类比,单循环链表也是一个圈,我们完全可以用它来模拟这个队伍。

定义结点、

为了还原,这里我就没有添加头结点,同时也避免了循环时对头结点的判断,避免了产生与普通数据结点不同的操作,保证所有结点都一样,操作没有差别。

继续阅读

数据结构-链表(1)

定义

链表是线性表的链接存储方式,相比于数组的连续存储

既然说到了线性表就来简单介绍一下,以便和后面的树,图等非线性结构区分开来

同一线性表中元素具有相同特性。
相邻数据元素之间存在序偶关系。
除第一个元素外,其他每一个元素有一个且仅有一个直接前驱元素。
除最后一个元素外,其他每一个元素有一个且仅有一个直接后继元素。

优缺点

优点

对于插入和删除元素,数组的时间复杂度为O(n),而链表为O(1)
链表长度可变,而数组长度不可变

缺点

按序号查找时,数组可以随机访问,时间复杂度为O(1),而链表不支持随机访问,时间复杂度为O(n)
存储密度(结点数据本身所占的存储量/结点结构所占的存储总量)<1
需要动态申请管理内存,处理不当会造成内存泄漏

分类

单链表
静态链表
循环链表
双向链表

专业术语

头节点:第一个有效节点之前的节点数据域不存放数据加头节点的目的主要是方便对链表的操作
首节点:第一个存放数据的节点
尾节点:最后一个存放数据的节点
头指针:指向头节点的指针
尾指针:指向尾节点的指针

继续阅读

数据结构-树(1)

这是一篇讲述概念的博客,但是如果你能看完,那么恭喜你,你已经知道什么是树了

定义:有且只有一个称为根的节点,有若干个互不相交的子树,这些子树本身也是一棵树。通俗来讲树就是由节点和边组成,一个节点只能有一个父节点,但是可以有多个子节点。根节点没有父节点。

专业术语:

  • 度:节点拥有的子树的个数。如1的度为3;4的度为0
  • 路径:从一个节点顺着边走到另一个节点,所经过的节点的顺序就叫做路径
  • 叶节点:没有子节点的节点称为叶子节点(度为零),简称叶节点,也叫终端节点如4,5,6,7
  • 非叶节点(非终端节点):度不为0
  • 双亲:父节点
  • 子孙:以该节点为根节点的所有节点,如:除了1之外都是1的子孙
  • 兄弟:有相同的的父节点,如:5,6
  • 堂兄弟:父节点是兄弟,如:5和7,6和7
  • 深度:从根节点到最底层节点的层数称为深度,根节点是第一层,深度也叫最大层次,或者高。如:该树深度为3

继续阅读

排序

稳定排序:当两个元素相同时,排序后这两个元素相对位置不变则称为稳定排序,我们一般需要的都是稳定排序

排序和查找的关系:排序是搜索的前提,排序是重点

五种最常见的排序

冒泡排序
选择排序
插入排序
快速排序
归并排序

快速排序

以下gif来自该视频,虽然是java,但是讲的很棒bilibili
我们假设有一个队人,要让他们按照从小到大排队站好,我们可以这样做,先让最左边的人当作基准点,把队伍分成比他高的和比他矮的两部分这样56号的位置已经确定了,我们先看他的左边,是比他矮的小队,我们依然是让最左边的当作基准点,也就是8号,针对于它的小队,不再是全体小队,让比八号矮的站到他的左边,高的站到他的右边。

完成之后我们再对56号右边的小队进行同样的操作,其实就是递归

我们来看看每个元素的归位顺序

我们来看一下快排的伪算法

接下来我们就看一下如何实现,我们先定义两个变量i和j分别指向头部和尾部,我们先让j向左移动,直到遇到一个比p也就是基准点小的值,停止移动,我们再让i向右移动,直到遇到一个比p大的值停止移动,然后交换i和j的值

交换之后我们继续让j移动,直到遇到比p小的值,再让i移动,直到遇到比p大的值,交换 当最后i和j相等时,i的左边就是比p小的,i的右边就是比p大的,我们就可以把i和p交换位置上代码

  • 还有一种写法,只有一点微小的差别

在寻找基准点位置的时候我们先让j向左移,再让i向右移,最后交换i,j元素,我们也可以在j找到一个比p小的元素后就将他赋值个i,当i找到一个大于p的值的时候就赋值给j,最开始i就是基准点,赋值给了p,所以i的位置实际上已经空出来了,当把j赋值给i时,这个空被填上了,但是j又空了出来,这就是一个不断填坑的过程

  •  同样当你想用其它位置的数来做基准点也很简单,只要你把它和第一位交换就可以了

    有问题欢迎大家提问哦0。0 可以直接评论😂 也可以QQ🤣