Glide 简单流程分析

简介: 转载请标明地址 QuincySx: http://www.jianshu.com/p/cf8f8f90f621这篇文章是这个系列的第一篇文章,我第一次写这样连续系列的文章,我先一层一层的剥开 Glide ,如果谁有更好的想法欢迎提出。

转载请标明地址 QuincySx: http://www.jianshu.com/p/cf8f8f90f621


这篇文章是这个系列的第一篇文章,我第一次写这样连续系列的文章,我先一层一层的剥开 Glide ,如果谁有更好的想法欢迎提出。

需知:本篇没有贴出太多 Glide 代码来对照分析,只是一个最简单的流程

看完这篇文章你会得到什么:
这篇文章你将会看到 Glide 的基本运作流程


Glide 的基本用法 整篇文章都是按照此代码环境来讲解的

Glide.with(Activity).load(Url).into(ImageView);

各个流程对象的转换

首先我先说一下 Glide 在各个流程上对象的转换

  1. 首先调用 with() 方法 会返回 RequestManager 这个对象

  2. 然后调用 load() 此时会返回 DrawableTypeRequest 对象,但是这个地方要注意了 这个对象继承自 GenericRequestBuilder 对象,从词义上来看
    这个对象是生成『通用请求生成器』,其实它的作用和他的词义其实一样的(不得不给 Glide 作者点个赞)

  3. 然后调用 init() 方法会构建 ViewTarget 然后开始获取资源,缓存,读取缓存,变换等处理然后放在 ImageView 上面

具体分析每个步骤所做的事情

具体分析每个以下每个步骤

with 方法

这个方法主要是往当前 Activity 里面添加 Fragment 并注册生命周期监听器,构建 RequestManager 、如果 Glide 没有初始化,也会初始化 Glide (RequestManager 这个地方要注意了,这个对象是一个 Activity 会有一个 RequestManager 对象,他不是单例的,为什么呢可以去看源码)

  1. with() 这个方法有好几个重载、但是呢...不用管他、他无论传成什么都是干的一个事我就随便挑一个说了with(FragmentActivity activity),在方法里面调用 RequestManagerRetriever.get() 会获取 RequestManagerRetriever (这个类的作用是提供 RequestManager)的单例,然后调用 RequestManagerRetriever.get() 方法,获取 FragmentActivity 中的 FragmentManager 对象(不同的方法可能获取方法不同,这里我们直说这一种,其他的可以自己去看一下源码),然后把 SupportRequestManagerFragment 加入到当前的 Activity 中(添加这个 Fragment 的目的是为了监听当前 Activity 的生命周期、这里监听生命周期的作用是及时取消图片资源获取,转换的任务,以防止性能上的浪费),然后把 Fragment 的监听器取出来,构造出 RequestManager ,再把 RequestManager 放到 Fragment 里面(后面几个方法我没有提名字,只提了实现了什么,你们看一下源码就会懂)

  2. 构造 RequestManager 的时候会获取单例的 Glide,如果 Glide 没有初始化 他会通过 GlideBuilder 来构建 Glide 里面完成了一些 缓存、线程池、转换、资源获取以及转换的控制类 等等的东西,然后调用 new 出 Glide

  3. 在 Glide 的构造方法里 注册了一堆监听,以及类的提供者,注册不同类型的
    ModelLoader ,注册变换的类等等(这个方法好多东西我还不知道是干什么的 我搞清了会更新博客)

  4. 然后他就会读取 Manifest 的里面 value 为 “ GlideModule” 的所有 meta-data 标签,然后获取 key 通过反射的方式获取 GlideModule,然后调用 GlideModule.registerComponents() 方法,将 ModelLoader 注册进 Glide 并且替换掉相同类型的 ModelLoader (为什么会讲是会替换掉相同类型的 ModelLoader 呢,因为 load() 有好多重载,它是根据类型把不同类型的 ModelLoader 放到一个 Map 里供,解析使用,具体到 into 再细说),通过这种方式我们就能够在外部提供自己的解析器了

  5. ConnectivityMonitor 来判断有没有网络状态获取的权限 然后选择往 Fragment 的监听器里面放网络监听器,还是空监听器,如果当前 APP 有获取网络状态的权限,他就会在网络改变的时候,调用任务队列,会重新启动任务

load 方法 此处分析的是传入 String 参数 并且是个 URL 地址

这个方法主要功能是根据传入的参数类型返回相应的 ModelLoader ,维护请求队列、 Activity 生命周期监听器、等、并构建 DrawableTypeRequest 对象

1. 在fromString() 中调用 RequestManager.loadGeneric(Class<T> modelClass) 方法来获取 GenericRequestBuilder<T> 类,那么这个方法干了什么呢。
  1. 首先调用 Glide.buildStreamModelLoader() 方法,然后在方法里调用 buildModelLoader(modelClass, InputStream.class, context),再在方法里调用Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass) 他会现在 Glide 中获取 ModelLoader 的工厂(GenericLoaderFactory 这个类里面保存有 完整的 ModelLoader 列表,和缓存的 ModelLoader,这个类是在 Glide 的构造方法中 new 出来的,跟随 Glide 为单例),获取之后调用工厂的 buildModelLoader() 的方法,在这个方法中他首先获取 缓存的 ModelLoader 如果没有就读取整个 ModelLoader 列表来获取 ModelLoader,并且把这个 ModelLoader 缓存起来,以后再用的时候就可以快速读取
  2. 调用Glide.buildFileDescriptorModelLoader(modelClass, context) 方法,然后在这个方法里调用了 buildModelLoader(modelClass, ParcelFileDescriptor.class, context) 和上个步骤一样的方法,并传入了一个类型,具体就不多说了,流程一样
  3. 第三步他会构建出 new 出 DrawableTypeRequest 对象
2. loadGeneric() 调用完,回到 load 方法哪里他会调用 DrawableRequestBuilder 的 load(ModelType model) 方法,把泛型参数储存一下,在我们的分析环境下就是 String 类型的,到此为止 DrawableTypeRequest 就构建出来了,他是继承自 DrawableRequestBuilder 也继承自 GenericRequestBuilder,下一个步骤就密切和 这个类相关了

into 方法

这个方法比较重要

  1. 调用 into(ImageView view) 方法,他会先判断图片显示方式然后设置不同的变换,然后先调用 buildImageViewTarge() 方法,在方法里面再调用 ImageViewTargetFactory.buildTarget(Class<Z> clazz) 方法来生成 ViewTarget(ImageViewTargetFactory 类也是在 Glide 初始化的时候就生成了,在 buildTarget() 方法中的 clazz 参数是在 DrawableTypeRequest 的父类 DrawableRequestBuilder 中的构造中传入的是 GlideDrawable.class ),所以这个 switch 语句 最终获取的也是 GlideDrawableImageViewTarget 类,这个类的构造也只是 存储的一下 View 此时先不必深究
  2. ViewTarget 构建完了然后调用into(Y target) 方法(Y extends Target<TranscodeType>),然后判断当前是否是主线程、如果不是那就要蹦沙卡拉卡了,然后在 TargetView 中获取 Request 如果有则停止并移除,通过 buildRequest() 方法获取 Request 然后添加到 ViewTarget 中,添加到 RequestTracker 队列中,以及监听中,这一步的源码我贴出来,看最下面
  3. 第三步将下面源码片段的 buildRequest(target) ,这个方法里面有个判断他的意思是,如果用户没有设定 Request 的线程优先级,就默认(这个地方 Glide 的默认线程优先级是低于 UI 线程的,他就是怕影响 UI 线程,如果没有特殊要求建议不要改动),然后调用 buildRequestRecursive() 这个方法,这个方法首先判断用户是否设置过加载的资源是图片的缩略图(低配版的图片),下面两个判断都是和缩略图有关系,如果就按照咱们上下文环境,也就是最简单的流程他走的是 else 调用 obtainRequest() 方法,在方法里再调用 GenericRequest.obtain() 来构建 GenericRequest ,构建的详细过程就不说了大家自己看一下
  4. 第四步 RequestTracker.runRequest(request) 从词义上来看就是开始请求,实际呢,你只要知道这个方法是运行 Request 就行了(这段代码简单,你简单看一下就行,RequestTracker 的作用是暂停、开始、暂停或重新运行任务,他是和 Fragment 生命周期有关联的),然后调用 Request.begin() 方法改变 Request 的 状态,然后调用 onSizeReady() 方法再次修改 Request 的状态,获取各种加载器,调用 Engine.load() (这个类以及方法的作用是控制缓存获取资源等任务,下一篇会详细讲),你会发现 load 方法里面有个回调接口,他传递的是 this,他会继续调用 target.onLoadStarted(getPlaceholderDrawable()); 这个方法可以点进去看一下功能,就是把占位的图片加载到 View 上,我们再返回去看 Engine.load() 里面,他加载成功的时候会回调 onResourceReady(Resource<?> resource) 方法,因为我们回调传的是 this 所以回调了 GenericRequest.onResourceReady() 他会把资源加载到 ImageView 上去(这里是简单说了一下流程,下一篇会详说)
Request request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
requestTracker.runRequest(request);

小结

我自己本身没有读过这种类型的库,我都是看的 github 上面用到的库,没事简单的看一看。说一下感想吧!我一开始想看 Glide 的时候有点怕,不知道如何下手也怕读不明白,就下载了源码去简单的看一看。我读的思路就是这个库的入门用法Glide.with(Activity).load(Url).into(ImageView);最简单的语句,就慢慢的一点点的看,看他是怎么转换的每个步骤怎么走的,如果理不清楚可以依靠 Debug 调试,跟着他走一遍,我也是看了好几遍才找到头绪。坚持才会赢嘛,网上都说他们读了两天就差不多了,咱比不了啊!看了四五天就稍微有个头绪,慢慢看吧,坚持就是胜利!!!

我的理解还是有点浅薄同时文章写的也不熟练,欢迎各位提出问题

目录
相关文章
|
安全 JavaScript 前端开发
区块链钱包系统开发解决方案/需求设计/功能逻辑/案例详细/源码步骤
The development of a blockchain wallet system involves multiple aspects, and the following is the detailed logic for developing a blockchain wallet system:
如何将Markdown文章轻松地搬运到微信公众号并完美地呈现代码内容
相信有很多童鞋跟我一样,热衷于用Markdown来编写文章。由于其简单的语法和清晰的渲染效果,受到广大码农朋友们的推崇。但是,当我们想维护起自己的公众号时,公众号编辑器往往让我们费劲了脑汁。本人尝试了各种工具,比如:秀米一些在线提供多种不同样式的编辑器。虽然这些编辑器都能够完成编辑任务,但是效果并不理想。与我们所追求的简洁、清晰风格总是格格不入,尤其是对于代码的展示非常的不友好。所以,这里给大家推荐一个本站的在线工具,可以帮助大家快速地把Markdown文章转换成微信公众号支持的漂亮格式。
684 0
如何将Markdown文章轻松地搬运到微信公众号并完美地呈现代码内容
|
安全 测试技术 量子技术
量子计算硬件:超导量子比特的最新进展
量子计算作为信息技术的前沿领域,超导量子比特作为其核心组件,近年来取得了显著进展。本文介绍了超导量子比特的基本原理、制造与性能提升、最新技术成果及未来展望,展示了其在密码学、化学和材料科学等领域的潜在应用,预示着量子计算时代的到来。
|
SQL 关系型数据库 MySQL
实时计算 Flink版操作报错合集之程序初始化mysql没有完成就报错如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
518 58
|
机器学习/深度学习 存储 搜索推荐
GBDT+LR简介
GBDT+LR简介
218 0
|
Dubbo Java 应用服务中间件
springboot + dubbo + zookeeper入门到实战超级详解
springboot + dubbo + zookeeper入门到实战超级详解
469 0
|
供应链 安全 区块链
构建未来:智能合约在区块链技术中的应用与挑战
【5月更文挑战第29天】 随着区块链技术的不断演进,智能合约作为其核心创新之一,正逐渐改变着我们的商业逻辑和交易模式。本文深入探讨了智能合约的技术原理、实际应用案例以及面临的主要挑战。我们将从智能合约的定义出发,解析其如何通过自动执行合同条款来减少中间环节,提高交易效率。同时,文章还将审视智能合约在不同行业中的实际应用,包括金融服务、供应链管理和身份验证等。最后,本文将讨论智能合约目前存在的技术限制、安全性问题以及法律监管的挑战,并提出对未来智能合约发展的展望。
707 0
|
Android开发 异构计算
|
人工智能 自然语言处理 前端开发
如何构建全栈 AI 应用
本文展示任何具有基本编程知识的人都可以构建 AI 驱动的软件。 学习了如何使用 React 和 Nodejs 构建聊天机器人,我们讨论了每种技术的优缺点。 最后,我们构建了一个既实用又安全的聊天应用
438 0
如何构建全栈 AI 应用
|
算法 异构计算
基于FPGA的LMS自适应滤波器verilog实现,包括testbench
基于FPGA的LMS自适应滤波器verilog实现,包括testbench
556 0