span从入门到精通3 第三方工具类GifDrawable2

2024-05-29 00:32

本文主要是介绍span从入门到精通3 第三方工具类GifDrawable2,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上一篇span从入门到精通 第三方工具类GifDrawable 我们讲到了GifDrawable的初始化,为了防止大家对自定义drawable迷惑我在后面又补了一篇文章 span从入门到精通 自定义drawable,接下来我们继续分析初始化的东西怎么用他是如何处理的GifDrawable是如何对加载的gif的。

通过对自定义span的理解我们认识到对span来说最核心的处理是draw的处理在这里我们可以将我们效果要表达的元素画在界面上,同时我们也知道他有一个核心方法invalidateSelf();通过这个方法可以刷新界面,我们有道理想到gif的加载就是通过一个轮询不断获取gif的下一个帧,然后每隔一段时间调用invalidateSelf方法重绘界面在重绘过程中将取到的下一帧draw到界面上,这样我们就看到了动的gif了。

下面我们着重分析draw方法看看它是如何draw的(注意前方高能)

public void draw(@NonNull Canvas canvas) {final boolean clearColorFilter;if (mTintFilter != null && mPaint.getColorFilter() == null) {mPaint.setColorFilter(mTintFilter);clearColorFilter = true;} else {clearColorFilter = false;}if (mTransform == null) {canvas.drawBitmap(mBuffer, mSrcRect, mDstRect, mPaint);} else {mTransform.onDraw(canvas, mPaint, mBuffer);}if (clearColorFilter) {mPaint.setColorFilter(null);}if (mIsRenderingTriggeredOnDraw && mIsRunning && mNextFrameRenderTime != Long.MIN_VALUE) {final long renderDelay = Math.max(0, mNextFrameRenderTime - SystemClock.uptimeMillis());mNextFrameRenderTime = Long.MIN_VALUE;mExecutor.remove(mRenderTask);mRenderTaskSchedule = mExecutor.schedule(mRenderTask, renderDelay, TimeUnit.MILLISECONDS);}}

首先clearColorFilter这个东西设置颜色过滤器的一般我们不会去设置这些东西略过,下面就是设置CornerRadiusTransform这个东西如果我们不设置圆角这个东西也可以不用在看默认一般为null。
所以我们这里走的方法为canvas.drawBitmap(mBuffer, mSrcRect, mDstRect, mPaint);
我们着重分析这几个参数
1.mBuffer为我们需要画的bitmap
2.mSrcRect为我们要画的矩形区域(bitmap的绘制区域)
3.mDstRect为我们的bitmap相对屏幕的区域(这东西可以用盒子模型理解 mDstRect代表盒子放在屋子里什么地方mSrcRect代表盒子里面的东西是如何摆放的)
4.mPaint这东西就不用再解释了吧画笔
我们接下来向下看看它如何处理gif的绘制的

if (mIsRenderingTriggeredOnDraw && mIsRunning && mNextFrameRenderTime != Long.MIN_VALUE) {final long renderDelay = Math.max(0, mNextFrameRenderTime - SystemClock.uptimeMillis());mNextFrameRenderTime = Long.MIN_VALUE;mExecutor.remove(mRenderTask);mRenderTaskSchedule = mExecutor.schedule(mRenderTask, renderDelay, TimeUnit.MILLISECONDS);}

给mNextFrameRenderTime赋值为Long.MIN_VALUE,mExecutor.remove(mRenderTask);这里处理是将线程池内的mRenderTask清理掉,然后mRenderTaskSchedule = mExecutor.schedule(mRenderTask, renderDelay, TimeUnit.MILLISECONDS);可以看到我们的线程池又重新执行了task的处理。
看到这里我们有理由相信mRenderTask就是处理每一帧的关键所在,在上一篇文章中我们也提到了mRenderTask在启动过程中 mRenderTask.doWork();调用了都work的处理,我们再来到mRenderTask中去看看它是如何处理的。
接下来我们继续看

class RenderTask extends SafeRunnable {RenderTask(GifDrawable gifDrawable) {super(gifDrawable);}@Overridepublic void doWork() {final long invalidationDelay = mGifDrawable.mNativeInfoHandle.renderFrame(mGifDrawable.mBuffer);if (invalidationDelay >= 0) {mGifDrawable.mNextFrameRenderTime = SystemClock.uptimeMillis() + invalidationDelay;if (mGifDrawable.isVisible() && mGifDrawable.mIsRunning && !mGifDrawable.mIsRenderingTriggeredOnDraw) {mGifDrawable.mExecutor.remove(this);mGifDrawable.mRenderTaskSchedule = mGifDrawable.mExecutor.schedule(this, invalidationDelay, TimeUnit.MILLISECONDS);}if (!mGifDrawable.mListeners.isEmpty() && mGifDrawable.getCurrentFrameIndex() == mGifDrawable.mNativeInfoHandle.getNumberOfFrames() - 1) {mGifDrawable.mInvalidationHandler.sendEmptyMessageAtTime(mGifDrawable.getCurrentLoop(), mGifDrawable.mNextFrameRenderTime);}} else {mGifDrawable.mNextFrameRenderTime = Long.MIN_VALUE;mGifDrawable.mIsRunning = false;}if (mGifDrawable.isVisible() && !mGifDrawable.mInvalidationHandler.hasMessages(MSG_TYPE_INVALIDATION)) {mGifDrawable.mInvalidationHandler.sendEmptyMessageAtTime(MSG_TYPE_INVALIDATION, 0);}}
}

它的父类SafeRunnable继承runnable在执行run的处理过程中如果GifDrawable没有被回收执行了doWork的处理即我们的doWork也就是执行在run里面的处理。
第一行
final long invalidationDelay = mGifDrawable.mNativeInfoHandle.renderFrame(mGifDrawable.mBuffer);调用了底层处理去渲染帧并返回渲染时长,注意这里可是十分关键,即使在前面的draw中我们虽然看到了调用了drawBitmap的处理但是我们怎么也没有找到给bitmap赋值即给他一个帧图像之类的只是通过底层给了它一个宽高,让它能更好的控制外层布局,因此我们有理由相信这层处理就是走下一帧的处理在这里我们的线程池,handler包括drawable都是一个外层控制真正的绘制渲染就是在这个方法之后习性的
之后给mNextFrameRenderTime赋值下面的处理我们暂时可以忽略后面最关键的处理就是
mGifDrawable.mInvalidationHandler.sendEmptyMessageAtTime(MSG_TYPE_INVALIDATION, 0);这一行他通过mInvalidationHandler发送消息执行处理,下面我们来看这东西对消息的处理

@Overridepublic void handleMessage(final Message msg) {final GifDrawable gifDrawable = mDrawableRef.get();if (gifDrawable == null) {return;}if (msg.what == MSG_TYPE_INVALIDATION) {gifDrawable.invalidateSelf();} else {for (AnimationListener listener : gifDrawable.mListeners) {listener.onAnimationCompleted(msg.what);}}}

看到了吧这里调用了gifDrawable.invalidateSelf方法这样的话又会重新draw重新执行线程处理重新渲染帧这样我们就走完了一套完整的流程,由于是底层的绘制所以大大提高了程序执行效率,看完之后大家是不是有些恍然大明白的感觉,希望这篇博客能帮助到大家更好的理解这个框架,那接下来我又要继续讲span了,看看这个高性能的框架在span处理中有什么作为。
github链接点击这里

这篇关于span从入门到精通3 第三方工具类GifDrawable2的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1012135

相关文章

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

使用Java实现通用树形结构构建工具类

《使用Java实现通用树形结构构建工具类》这篇文章主要为大家详细介绍了如何使用Java实现通用树形结构构建工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录完整代码一、设计思想与核心功能二、核心实现原理1. 数据结构准备阶段2. 循环依赖检测算法3. 树形结构构建4. 搜索子

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件

jvm调优常用命令行工具详解

《jvm调优常用命令行工具详解》:本文主要介绍jvm调优常用命令行工具的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一 jinfo命令查看参数1.1 查看jvm参数二 jstack命令2.1 查看现场堆栈信息三 jstat 实时查看堆内存,gc情况3.1

MySQL使用binlog2sql工具实现在线恢复数据功能

《MySQL使用binlog2sql工具实现在线恢复数据功能》binlog2sql是大众点评开源的一款用于解析MySQLbinlog的工具,根据不同选项,可以得到原始SQL、回滚SQL等,下面我们就来... 目录背景目标步骤准备工作恢复数据结果验证结论背景生产数据库执行 SQL 脚本,一般会经过正规的审批

基于Python开发批量提取Excel图片的小工具

《基于Python开发批量提取Excel图片的小工具》这篇文章主要为大家详细介绍了如何使用Python中的openpyxl库开发一个小工具,可以实现批量提取Excel图片,有需要的小伙伴可以参考一下... 目前有一个需求,就是批量读取当前目录下所有文件夹里的Excel文件,去获取出Excel文件中的图片,并

Java导入、导出excel用法步骤保姆级教程(附封装好的工具类)

《Java导入、导出excel用法步骤保姆级教程(附封装好的工具类)》:本文主要介绍Java导入、导出excel的相关资料,讲解了使用Java和ApachePOI库将数据导出为Excel文件,包括... 目录前言一、引入Apache POI依赖二、用法&步骤2.1 创建Excel的元素2.3 样式和字体2.