Android事件分发

2023-05-16

基本知识
什么是触摸事件
触摸事件,是Android用来描述你的手对屏幕做的事情的最小单元。关键词有两个:手势(你的手对屏幕做的事情)、最小单元。

所谓手势,就是比如按下、移动、抬起、点击事件、长按事件、滑动事件。
所谓最小单元,就是不可再拆分的,比如按下(down)、移动(move)、抬起(up)就是不可再拆分的。而点击事件、长按事件、滑动事件则是由那些不可再拆分的事件组合起来的。比如点击事件是由按下、抬起组成的。长按事件是按下并保持一段时间不动。注意一下滑动事件和移动(move)的区别,滑动事件可以理解为是由若干个“move”组合起来的,系统对触摸的捕捉是很灵敏的,手指放在屏幕上稍微抖一下,都会产生“move”事件。用手指在屏幕上滑一段距离,我们感觉是一次滑动,但是系统已经产生了很多个“move”事件。
我们会遇到的触摸事件,大多就是按下(down)、移动(move)、抬起(up),有时候你可能会遇到取消(cancel)事件,但是事件分发重点关注的大多都是前三者。

MotionEvent对象
一个触摸事件包括事件类型和坐标两类信息:

事件类型(包括但不局限于):ACTION_DOWN(按下)、ACTION_ MOVE(移动)、ACTION_ UP(抬起)。
坐标:坐标还分参考系,有以屏幕作为参考系的坐标值,也有以被触摸的View作为参考系的坐标值。
站在面向对象的角度,MotionEvent对象就是对触摸事件相关信息的封装,这两类信息在MotionEvent对象里面都能找到。motionEvent.getAction()可以获得事件类型,每个类型在MotionEvent里都有对应的常量,motionEvent.getRawX()、motionEvent.getRawY()可以获得以屏幕作为参考系的坐标值,motionEvent.getX()、motionEvent.getY()可以获得以被触摸的View作为参考系的坐标值。

一个完整的事件序列
注意区分一个触摸事件和一个完整的事件序列两个概念。当手指在屏幕上按下、抬起,会产生一系列事件:ACTION_DOWN(一个)–>ACTION_MOVE(数量不定)–>ACTION_UP(一个),从ACTION_DOWN到ACTION_UP,称为一个完整的事件序列,即某一次手指按下到手指抬起算是一个完整的事件序列,下一次手指按下到抬起是另一个完整的事件序列。

笔者没有真的考究过Android官方是不是真的有“事件序列”这么一个概念性的名词,只是这个名词在一些讲解事件分发的博客里面有出现过。但是在ViewGroup的源码里面,确实是可以找到在遇到ACTION_DOWN时清除某些标记位(以避免受到前一个事件序列的影响),在非ACTION_DOWN的情况下,某次触摸事件传递受前一次触摸事件处理结果的影响之类的行为,确实反映了两个相邻的ACTION_DOWN和ACTION_UP之间的事件处理是有关联,下一个ACTION_DOWN会尽量和前一个ACTION_UP相互独立的情况。所以我们是可以认为确实有“事件序列”这么一个逻辑存在。

那么为什么要有事件序列这种处理逻辑呢,在搞懂了事件分发的流程之后,笔者个人的看法是,这是为了让Android在处理触摸事件的时候尽量“拟人化”。怎么就拟人化了呢,触摸事件是站在计算机的角度来看手势的,而事件序列是站在人(严格来讲是用户那种人,不是程序员那种人)的角度来看待手势的。比如我们点击一个按钮,人的反应应该是“我就点了一下”,而不是“我先按下、然后抬起”。比如刷新闻、刷资讯的动作,人的反应应该是“我向上滑了一下”,而不是“我先按下、然后向上移动了若干次(若干个ACTION_ MOVE事件),然后我抬起手”。将两个相邻的ACTION_DOWN和ACTION_UP及其中间所有的事件联系在一起,在需要的时候关联处理,这种结果更加符合人的感受,有更好的用户体验。

为什么要有事件分发
简单地讲,事件分发就是为了解决“谁来干活”的问题。当一个事件发生,有超过一个View(或者ViewGroup)能够对它进行响应(处理)时,就要确定到底谁来处理这个事件。比如下图:

为什么要有事件分发

如果触摸事件发生在点A,那么毫无疑问是由ViewGroup来处理的。如果触摸事件发生在点B,那就要确定到底是ViewGourp还是View来处理这个事件。

View事件分发
这里要讲的View的事件分发,是指View.java源码里对触摸事件进行传递的流程。

流程图
声明,以下关于View事件分发的流程图是根据Android源码2.3.7版本绘制的。流程如下图所示:

View事件分发

流程说明
View没有子View,不存在拦截行为,所以View的事件分发比较简单。

从dispatchTouchEvent()开始,进入当前View的事件分发流程,该方法只负责分发事件,没有实际进行事件处理。
有可能处理事件的有两个地方,一个是外部设置的OnTouchListener监听器,即OnTouchListener的onTouch(),一个是View内部的处理方法,即onTouchEvent()。而且外部设置的监听器优先获取事件。
当外部设置的监听器处理了事件(即有设置监听器、View处于ENABLE状态、监听器在onTouch()里面返回true三者均成立),dispatchTouchEvent()返回true,当前View的onTouchEvent()不会触发。
如果外部的监听器不处理事件,则dispatchTouchEvent()的返回值由View自己的onTouchEvent()决定。
注意一下,对于上级ViewGroup(也就是当前View的父容器)而言,它只认识子View的dispatchTouchEvent()方法,不认识另外两个处理事件的方法。子View的OnTouchListener和onTouchEvent()都是在自己的dispatchTouchEvent()里面调用的,他们两个会影响dispatchTouchEvent()的返回值,但是对于上级ViewGroup而言,它只认识dispatchTouchEvent()的返回值就足够了。

ViewGroup事件分发
这里要讲的ViewGroup的事件分发,是指ViewGroup.java源码里对触摸事件进行传递的流程。

流程图
声明,以下关于ViewGroup事件分发的流程图是根据Android源码2.3.7版本绘制的。这个流程图只是描述了事件分发的主要流程,言下之意如果你拿源码过来对照,你会发现有些东西这个流程图里面没有体现。比如对于ACTION_UP和ACTION_CANCEL事件有些清空标志位的逻辑在流程图里是没有的,比如把触摸事件传给子View时对触摸坐标进行转变的逻辑也没体现。笔者认为相对于事件传递本身而言,这些细枝末节的东西画出来既没有加大我们对事件传递的理解,还增加了理解复杂度,所以省略。

流程如下图所示:

ViewGroup事件分发

ViewGroup事件分发的特点(规律)
相对于View的事件分发,ViewGroup的就明显复杂多了。在说明这幅图之前,笔者先给出这幅图里面的特点,有了这些特点,你就不会觉得混乱。就笔者的梳理而言,ViewGroup的事件分发可以总结有这样几个特点:

ViewGroup的事件分发“基于”责任链模式,同时是不纯的责任链模式。之所以说是“基于”是因为事件分发其实和责任链模式不完全相同,应当说事件分发的流程更加复杂一些。
同一个事件序列里面的不同触摸事件之间的影响,通过变量target、disallowIntercept来实现,所以这两个变量的情况会影响事件的传递流程,这也是和一般的责任链模式不同的地方。
ACTION_DOWN事件在传递的同时,执行着“寻找target”的任务。而非ACTION_DOWN事件则在使用target(如果有target),即根据target以及和target相关的东西(disallowIntercept)控制事件传递流程。
事件的传递有“抛回来”的行为,就像是两个相邻的节点之间推卸责任。ViewGroup和它的target(如果有)之间就像在对话:“这锅你背”、“你背你背,不用客气”。
为什么要梳理这些规律?我们从事件分发的流程总结出规律,再通过这些规律倒回去理解事件分发的流程为什么要这样设计。在接下来的流程说明里面,我们通过具体流程来理解这几个特点。对于上图我们采取自上而下,从左向右的顺序来看。每一个触摸事件相当于责任链模式里面的一个请求,每一个ViewGroup或者是子View相当于责任链模式里面的一个处理器(处理者),在流程说明当中笔者会不断地对流程图、责任链模式、上面说的几个特点这三者进行对比,以加深理解。

流程说明:ACTION_DOWN事件
我们先来看ACTION_DOWN事件的流程:

ACTION_DOWN事件流程图

流程说明:

从ViewGroup的dispatchTouchEvent()开始,进入当前ViewGroup的事件分发流程。
首先要做的事情,自然是判断是不是迎来了一个新的事件序列,所以要判断该事件是否是ACTION_DOWN事件。
如果是ACTION_DOWN事件,作为一个事件序列的开头,应当要消除前面的事件序列可能留下的影响,所以接下来做的事情就是清空target。既然没有了target,自然也就不需要考虑disallowIntercept的影响,所以整个ACTION_DOWN事件里面没有去根据target和disallowIntercept的情况进行事件传递的。
接下来的事情就和一般的责任链模式类似,onInterceptTouchEvent()就像在责任链模式里面某个处理器判断是否处理当前请求,如果不处理(即不拦截),就沿着责任链往后传。
事件传给了子View,如果子View处理了,ViewGroup就找到target了,同时由于返回true,当前ViewGroup成了上级ViewGroup的target,找到了target就相当于找到了同个事件序列的后续触摸事件的“背锅侠”。
现在我们回退一步,如果子View不处理,这个“锅”就得ViewGroup自己担着,这就是我们前面说的“推卸责任”的特点。所以事件会传递到super.dispatchTouchEvent()。ViewGroup类继承自View类,也就是进入了前文说的View事件分发流程,就相当于询问当前ViewGroup自己是否处理这个事件,细节这里就不重复了。如果当前ViewGroup自己处理了,对于上级ViewGroup而言,还是找到了target,如果当前ViewGroup不处理,这个“锅”继续抛给上级ViewGroup。
接着继续回退一步,如果拦截了,就和一般的责任链模式类似,所以就不需要经过子View,直接由ViewGroup自己处理该事件。如果处理了,则当前ViewGroup就是上级ViewGroup的target,否则,事件还是抛回给上级ViewGroup。
以上,ACTION_DOWN事件的传递就说完了。简单地讲,ACTION_DOWN事件传递的最终结果,就是为ViewGroup找到target,如果找到了,target就是后续触摸事件的“背锅侠”,如果找不到,当前ViewGroup选择是否成为上级ViewGroup的target。

流程说明:除了ACTION_DOWN以外的事件
接下来看非ACTION_DOWN事件的流程:

非ACTION_DOWN事件流程图

流程说明:

既然ACTION_DOWN事件负责寻找target,那么非ACTION_DOWN事件做的第一件事,就是看看有没有target。这里也体现了同个事件序列里面某个触摸事件受前面的触摸事件的影响。
如果没有“背锅侠”(没有target),那这个锅就得当前ViewGroup自己担着,所以直接传递给了super.dispatchTouchEvent()。从这里你可以看出,如果在ACTION_DOWN里面没有找到target,那么同个事件序列后续的所有事件,都不会再有“背锅侠”,都是当前ViewGroup自己担着(如果ViewGroup能收到这些事件的话)。将target指向某个子View这个行为,只在ACTION_DOWN里面才有可能发生。
对于有target的情况,你从图里可以看到,往下总共分了三条路线:右边的路线是禁止拦截、左边的路线是不禁止拦截然后拦截、中间的路线是不禁止拦截然后不拦截。接下来我们单独对这共计三个情况进行说明,因为从有target开始往下走,才是我们在处理事件冲突的时候最经常遇到的情况。
流程说明:对于有target情况下的事件传递
接下来看在非ACTION_DOWN事件时,对于有target情况下的事件传递流程说明:

首先说明一下disallowIntercept变量,它是一个boolean类型的变量,表示子View是否禁止拦截触摸事件。它的取值,可以通过ViewGroup的requestDisallowInterceptTouchEvent(boolean)来修改,这个方法是public修饰的,如果子View在前一个触摸事件里面通过调用该方法设置了禁止拦截标识,后续的事件就会直接传给子View。注意一下,如果这个标识为禁止拦截,说明子View必须要这个事件,但是如果标识为不禁止拦截,并不是说明子View就不要这个事件了,只能认为子View“还没确定”要它。什么叫做“还没确定”要?我们举个例子来谈这个问题。
如果现在要你自己处理类似ViewPager嵌套ListView(即ViewGroup要横向滑动,里面的子View要竖向滑动)的冲突,基本思路是比较简单的,ViewGroup和子View均捕获触摸事件,如果ViewGroup发现是横向滑动,就拦截并且处理。如果子View发现是竖向滑动,就设置disallowInterceptTouchEvent为禁止拦截,然后自己处理事件。那么紧接着的问题就是,如何发现横/竖向滑动?自然是收集若干个触摸事件,然后根据这几个连续的触摸事件分析手指到底是朝哪个方向滑动。那么在你能够确定用户在朝哪个方向滑动之前,ViewGroup和子View都处于“迷茫”状态:它们两者均不知道手指到底朝哪滑动,也就是它们均不知道自己到底要不要处理这些事件。我们之前讨论事件传递过程的时候总在说如果ViewGroup要处理(或者不要处理),如果子View要处理(或者不要处理),而事实是存在这样一个情况:有段时间它们两者均不知道自己要不要处理这个事件。这个时候怎么办呢?合理的作法应当是让事件继续流经ViewGroup和子View,直到其中一方做出处理。此时,子View不应该禁止ViewGroup拦截事件,同时,ViewGroup也不应该拦截事件。这样,触摸事件就会经过中间这条路线:不禁止拦截然后不拦截。所以这条路线,是用来服务于ViewGroup和子View都还没确定要不要处理事件的情况。
如果子View认为手指是在竖向滑动,它决定要处理事件,它就会将diallowInterceptTouchEvent设置为禁止拦截,事件的传递就会走向右边的路线。自此,同一个事件序列后面的所有触摸事件,都会交给子View处理。
如果ViewGroup认为手指是在横向滑动,它就要拦截并处理后续事件,事件的传递就会走向左边的路线,于是后续事件不再需要传给子View,所以会将target置空。接着要告诉上级ViewGroup,自己需要接手这些事件,于是返回true。接下来的行为和ACTION_DOWN事件在拦截之后的行为有些不同,刚刚被拦截下来的事件并不传给super.dispatchTouchEvent(),后续的事件才会传给 super.dispatchTouchEvent()。这个行为笔者是这样理解的,从ACTION_DOWN开始,到最后一个流经onInterceptTouchEvent()事件之间的所有事件,构成了一个判断条件(类似开关),这个判断条件供onInterceptTouchEvent()用来判断是否拦截后续事件,这些判断条件本身是不需要被处理的,它们只是用来提供判断的,在这些判断条件之后的事件,才是需要处理的。所以是在被拦截的事件之后的事件,才开始流向super.dispatchTouchEvent()。
事件分发的应用套路

ViewGroup事件分发重复贴图
这里主要说的是两级View(一个ViewGroup和里面一个子View)的情况下,如何根据实际需要控制事件传递。所谓的套路,其实还是说规律,但是我们前面已经说了事件传递的规律了,所以现在说的是实际操作时的使用规律。为了方便阅读,重新把图再贴一次:

我们分几大类情况来说,旨在说明在不同的情况下,应该如何选择不同支路,也就是控制事件传递的流程。

ViewGroup需要一切事件:只有你的ViewGroup明确需要一切触摸事件,而且不打算传递给任何子View的时候,会在ACTION_DOWN事件里面拦截事件,这样所有的事件都会传给ViewGroup自己,并且不会下发给任何子View。此时从一开始就要选择的路线是:ACTION_DOWN事件–>onInterceptTouchEvent()拦截–>super.dispatchTouchEvent()处理。后续事件全部传给super.dispatchTouchEvent()。
子View需要一切事件:只有你的子View明确需要一切事件,而且不打算让ViewGroup处理任何事件的时候,要求ViewGroup不要拦截ACTION_DOWN事件,子View必须处理ACTION_DOWN事件,并且设置disallowIntercept标记为禁止拦截。此时从一开始需要走的路线是:ACTION_DOWN事件–>onInterceptTouchEvent()不拦截–>子View处理并且设置disallowIntercept为禁止拦截。后续事件全部传给子View,ViewGroup不会再有机会拦截。
ViewGroup和子View只需要特定情况下的事件(就好比前面我们说的例子,横竖两个方向的事件冲突):此时对于ACTION_DOWN事件,ViewGroup不能拦截,子View必须处理,这样才能保证两者均能收到后续事件。对于ACTION_DOWN以外的事件,在两者都还没能决定是否要处理事件的时候,需要走的路线是:有target–>不禁止拦截–>不拦截–>传给子View的dispatchTouchEvent()。这样能够让ViewGroup和子View均能不断收集事件,以便进行是否处理的判断。一旦子View决定要处理事件,设置disallowIntercept为禁止拦截,避免后续事件被ViewGroup拦截。一旦ViewGroup决定要处理事件,在onInterceptTouchEvent()里面进行拦截,避免后续事件被子View抢走。
至此,我们已经分析完了常见的事件处理需要流经的路线,从实际需求的角度出发反过去看事件传递,你是否能更深入地理解ViewGroup的事件分发为什么要设计成这样呢?

总结
正如本文开头所说,本文的侧重点是通过流程图来分析Android事件分发,除了文章开头介绍一些基本知识,全文基本都在说明流程图。

ViewGroup的事件分发是Android事件分发的重点,也是本文花最大篇幅描述的内容。不单止要说清楚ViewGroup的事件分发流程,还要说清楚这个流程有什么规律、为什么要这么设计、流程上的每个节点都在干什么。最后,站在实践的角度,说明在面对不同需求的时候,该如何选择流程图里的不同路线,实现需求。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android事件分发 的相关文章

  • 如何为ScrollView放置固定图像背景?

    我应该想要滚动视图滚动 而不是背景中的图像 将图像添加到滚动视图框架之前的视图层次结构的较高位置
  • 在包“android”中找不到属性“backgroundTint”的资源标识符

    我发现了一些视图 xml 属性 例如backgroundTint backgroundTintMode 但是当我使用它作为视图属性定义时 Eclipse 显示错误 No resource identifier found for attri
  • Sqlite数据库生命周期?关闭应用程序后它会被删除吗?

    我正在遵循一个简单的教程 该教程创建一个从 SQLiteOpenHelper 扩展的类 并创建一个包含一个表和 5 行的数据库 好的 但我需要更多地了解 android Sqlite 数据库 例如 如果应用程序关闭或手机关机会发生什么 数据
  • SearchView过滤ListView

    我已经实现了搜索视图来过滤我的列表视图项目 当我输入任何文本时 它会过滤列表 但当我退出搜索视图时 它不会返回原始列表项 public class PlacesListAdapter extends ArrayAdapter
  • Android 30+ 中的视频捕获意图 - 只有所有者才能与待处理项目交互

    我正在尝试在我的应用程序上捕获视频 它可以在 android API 30 以下运行 但不能在 30 以上运行 似乎在 sdk 30 之后 android 不允许完全读取外部存储 作用域存储 我目前遇到这个错误 java lang Ille
  • CardView 圆角获得意想不到的白色

    When using rounded corner in CardView shows a white border in rounded area which is mostly visible in dark environment F
  • 无法获取log.d或输出Robolectrict + gradle

    有没有人能够将 System out 或 Log d 跟踪从 robolectric 测试输出到 gradle 控制台 我在用Robolectric Gradle 测试插件 https github com robolectric robo
  • 如何在android中获取Camera2 API的当前曝光

    In android hardware Camera旧的 我使用下面的代码获取当前曝光并获取它Camera Camera Parameters param mCamera getParameters currentExposure para
  • 当文本输入聚焦在 React Native for Android 的底部工作表上时,视图移出屏幕

    我正在使用图书馆 https github com osdnk react native reanimated bottom sheet https github com osdnk react native reanimated bott
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • 原色(有时)变得透明

    我正在使用最新的 SDK 版本 API 21 和支持库 21 0 2 进行开发 并且在尝试实施新的材料设计指南时遇到了麻烦 材料设计说我需要有我的primary color and my accent color并将它们应用到我的应用程序上
  • Ubuntu 16.04 - Genymotion:找不到 /dev/hw_random

    I install Genymotion on the Ubuntu 16 04 64Bit I created a virtual emulator for Android 6 0 then I run this emulator but
  • Google 云端硬盘身份验证异常 - 需要许可吗? (v2)

    我一直在尝试将 Google Drive v2 添加到我的 Android 应用程序中 但无法获得授权 我收到 UserRecoverableAuthIOException 并显示消息 NeedPermission 我感觉 Google A
  • 如何使用InputConnectionWrapper?

    我有一个EditText 现在我想获取用户对此所做的所有更改EditText并在手动将它们插入之前使用它们EditText 我不希望用户直接更改中的文本EditText 这只能由我的代码完成 例如通过使用replace or setText
  • 字符串数组文本格式化

    我有这个字符串 String text Address 1 Street nr 45 Address 2 Street nr 67 Address 3 Street nr 56 n Phone number 000000000 稍后将被使用
  • Android Studio - Windows 7 上的 Android SDK 问题

    我对 Google i o 2013 上发布的最新开发工具 Android Studio 有疑问 我已经成功安装了该程序并且能够正常启动 我可以导入现有项目并对其进行编辑 但是 当我尝试单击 SDK 管理器图标或 AVD 管理器图标时 或者
  • 增加活动的屏幕亮度

    显然 Android 操作系统中至少有三种不同的技术可以改变屏幕亮度 其中两个在纸杯蛋糕之后不再起作用 而第三个被接受的技术显然有一个错误 我想在单视图活动开始时增加屏幕亮度 然后在活动结束时将亮度恢复为用户设置 没有按钮 没有第二个视图或
  • 实现滚动选择 ListView 中的项目

    我想使用 ListView 您可以在其中滚动列表来选择一个项目 它应该像一个 Seekbar 但拇指应该是固定的 并且您必须使用该栏来调整它 我面临的一个问题是 我不知道这种小部件是如何调用的 这使得我很难搜索 所以我制作了下面这张图片 以
  • 将 Intent 包装在 LabeledIntent 中以用于显示目的

    要求 我的应用程序中有一个 共享 按钮 我需要通过 Facebook 分享 我需要选择是否安装原生 Facebook 应用程序 我们的决定是 如果未安装该应用程序 则将用户发送到 facebook com 进行分享 当前状态 我可以检测何时
  • 捕获的图像分辨率太大

    我在做什么 我允许用户捕获图像 将其存储到 SD 卡中并上传到服务器 但捕获图像的分辨率为宽度 4608 像素和高度 2592 像素 现在我想要什么 如何在不影响质量的情况下获得小分辨率图像 例如我可以获取或设置捕获的图像分辨率为原始图像分

随机推荐

  • docker安装使用系列二之容器、镜像、仓库使用实例分析

    可能大家对docker了解不深 xff0c 这里再简单赘述一下docker这款利器 1 什么是docker Doker是基于GO语言实现的云开源项目 xff0c 通过对应用组件的封装 分发 部署 运行等生命周期的管理 xff0c 达到应用组
  • 图像处理之opencv库使用小结

    OpenCV是一个基于BSD许可 xff08 开源 xff09 发行的跨平台计算机视觉库 xff0c 可以运行在Linux Windows Android和Mac OS操作系统上 它轻量级而且高效 由一系列 C 函数和少量 C 43 43
  • react 启动项目遇到的问题

    当启动react 项目时遇到 xff1a 39 react scripts 39 不是内部或外部命令 xff0c 也不是可运行的程序 npm install npm install 下载依赖遇到安装失败 xff0c 则依赖包删除不干净 xf
  • Android LED电子表时钟字体digital font

    字体效果如下图所示 xff1a 这种类型的字体样式会被一些UI设计用于Android APP中时钟显示 xff0c 比如交通灯倒计时 实现这种字体样式 xff0c 先导入一个字体包 xff1a digital ttf 这个digital t
  • Android音视频处理之MediaCodec

    MediaCodec是Android中媒体编解码器 xff0c 可以对媒体进行编 解码 MediaCodec采用同步 异步方式处理数据 xff0c 并且使用了一组输入输出缓存 xff08 ByteBuffer xff09 通过请求一个空的输
  • 计算相机投影矩阵(含代码)(Python)

    计算相机投影矩阵 xff08 含代码 xff09 xff08 Python xff09 前几天处理点云时 xff0c 需要使用到像片与3D点云的对应关系 在这边找了一圈没有发现直接可用的代码 xff0c 于是去GitHub试了一下 xff0
  • H264 SPS中得到宽高的代码(java)

    数据需要去掉头 xff0c SPS测试数据 byte buffer 61 new byte 103 66 64 12 38 5 7 56 7 124 2 得到结果宽320高240 public class H264SpsParser pri
  • git 调换提交顺序

    前两个commit交换顺序 1 查看提交历史 git log oneline 2 把要调整顺序的commit显示在vim中 git rebase i a33d521 a33d521用来确定commit范围 xff0c 表示从此提交开始到当前
  • android hmacSha256 加密

    public class HMACSHA256 public static String hmacSha256 String KEY String VALUE return hmacSha KEY VALUE 34 HmacSHA256 3
  • Java生成固定长度的随机字符串(以大小写字母和数字)

    public class RandomStringUtil public static ArrayList lt String gt strList 61 new ArrayList lt String gt public static R
  • Android reckon 控制项目打包版本

    reckon 用法 github地址 xff1a https github com ajoberstar reckon 根项目 gradle配置 buildscript apply from 39 versions gradle 39 re
  • ArrayList源码解析

    构造函数 Constructs an empty list with an initial capacity of ten 使用10个初始容量构造一个空的集合 public ArrayList super 用一个空的数组进行初始化 this
  • 2023年有效的rtsp,rtmp,hls流媒体测试地址整理汇总

    rtsp rtsp wowzaec2demo streamlock net vod mp4 BigBuckBunny 115k mov 已停用 rtsp wowzaec2demo streamlock net vod mp4 BigBuck
  • http请求

    HTTP请求报文 一个HTTP请求报文由请求行 xff08 request line xff09 请求头部 xff08 header xff09 空行和请求数据4个部分组成 1 请求行 请求行分为三个部分 xff1a 请求方法 请求地址和协
  • http响应报文

    HTTP响应报文主要由状态行 响应头部 空行以及响应数据组成 1 状态行 由3部分组成 xff0c 分别为 xff1a 协议版本 xff0c 状态码 xff0c 状态码描述 其中协议版本与请求报文一致 xff0c 状态码描述是对状态码的简单
  • centos7+jdk8+安装Elasticsearch6.0

    一 xff1a 为Elasticsearch准备用户 1 添加用户 Elasticsearch6 0需要使用非root用户启动 root 64 66 adduser ela root 64 66 passwd ela 2 授权用户 查看文件
  • Retrofit2 源码解析

    0 基本使用 1 Retrofit 将我们的 HTTP API 转换成一个 接口形式 所以我们第一步定义一个 interface public interface GitHubService 64 GET 34 user user repo
  • Android Studio插件的源文件位置——mac端

    有些时候安装插件后 xff0c 整个android studio都卡住了 xff0c 无法通过Android Studio gt preferences gt plugins来卸载 xff0c 这时候就需要找到安装位置 xff0c 进行删除
  • H.264编码基础知识详解

    一 编码基础概念 1 为什么要进行视频编码 xff1f 视频是由一帧帧图像组成 xff0c 就如常见的gif图片 xff0c 如果打开一张gif图片 xff0c 可以发现里面是由很多张图片组成 一般视频为了不让观众感觉到卡顿 xff0c 一
  • Android事件分发

    基本知识 什么是触摸事件 触摸事件 xff0c 是Android用来描述你的手对屏幕做的事情的最小单元 关键词有两个 xff1a 手势 xff08 你的手对屏幕做的事情 xff09 最小单元 所谓手势 xff0c 就是比如按下 移动 抬起