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

相关文章

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

sqlite3 命令行工具使用指南

《sqlite3命令行工具使用指南》本文系统介绍sqlite3CLI的启动、数据库操作、元数据查询、数据导入导出及输出格式化命令,涵盖文件管理、备份恢复、性能统计等实用功能,并说明命令分类、SQL语... 目录一、启动与退出二、数据库与文件操作三、元数据查询四、数据操作与导入导出五、查询输出格式化六、实用功

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

Oracle 数据库数据操作如何精通 INSERT, UPDATE, DELETE

《Oracle数据库数据操作如何精通INSERT,UPDATE,DELETE》在Oracle数据库中,对表内数据进行增加、修改和删除操作是通过数据操作语言来完成的,下面给大家介绍Oracle数... 目录思维导图一、插入数据 (INSERT)1.1 插入单行数据,指定所有列的值语法:1.2 插入单行数据,指

基于Python开发Windows屏幕控制工具

《基于Python开发Windows屏幕控制工具》在数字化办公时代,屏幕管理已成为提升工作效率和保护眼睛健康的重要环节,本文将分享一个基于Python和PySide6开发的Windows屏幕控制工具,... 目录概述功能亮点界面展示实现步骤详解1. 环境准备2. 亮度控制模块3. 息屏功能实现4. 息屏时间

MySQL DQL从入门到精通

《MySQLDQL从入门到精通》通过DQL,我们可以从数据库中检索出所需的数据,进行各种复杂的数据分析和处理,本文将深入探讨MySQLDQL的各个方面,帮助你全面掌握这一重要技能,感兴趣的朋友跟随小... 目录一、DQL 基础:SELECT 语句入门二、数据过滤:WHERE 子句的使用三、结果排序:ORDE

SQLite3命令行工具最佳实践指南

《SQLite3命令行工具最佳实践指南》SQLite3是轻量级嵌入式数据库,无需服务器支持,具备ACID事务与跨平台特性,适用于小型项目和学习,sqlite3.exe作为命令行工具,支持SQL执行、数... 目录1. SQLite3简介和特点2. sqlite3.exe使用概述2.1 sqlite3.exe

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1