这是一篇为阅读glide的帮助文章,不细讲,意在说明一些类的功能和整个流程。
在看这篇前,请先去看下面的链接
细讲资源:
https://blog.csdn.net/guolin_blog/article/details/53759439
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2018/0403/9555.html
https://www.jianshu.com/p/5c8ce241199e
介绍:
Glide是一个的图片加载框架,使得我们可以在Android平台上以极度简单的方式加载和展示图片。
简述其功能:
Glide 帮助我们有简洁的代码,完成了对图片网络访问、内缓存、磁盘缓存、不同形式的展示。
我们按照上图的链式调用顺序分析其功能:
1. 完成glide的前提条件:glide.with()
首先要解决如何让glide框架,能够与展示的它容器(eg,activity)共存亡。不能让容器都被销毁了,我们还持有glide对象。这样就浪费内存了。
glide.with()帮助我们向其容器加入一个fragment,由于监听容器的生命周期,从而决定是否暂停或销毁glide. 最后放回给我们一个RequestManager,顾名思义请求的管理类。我们分析其成员变量。
我们可以看到其几个重要的成员变量。
lifecycle ---有与监听容器状态的改变,并调用自己重写的onStart、onStop、onDestory.
treeNode ---响应容器的暂停和恢复请求,为其提供操作请求的方法。
requestTracker --- 实际去操作请求的对象。扩充下:如何控制的???requestTracker中有一个成员变量requests,存放着 所有所有的请求,遍历requests,找到isRunning的请求。 改变其状态。并将其放入pendingRequests.
glide ---这个是个重器。
optionsApplier ---调用的options,将传入builder(DrawableTypeRequest)。
options ---让开发者重写,意在拿到builder(DrawableTypeRequest),做一些操作。
小结1:RequestManager为glide提供同步容器的服务。并且
2. 前期准备:load()
对于load前期的准备,就是创建能处理请求的工具类。
节点C: 准备分为两部分
先分析fromString()
节点B:
在RequestManager中,创建了满足不同类型请求的不同工具类,然后将这些工具封装到DraeableTypeRequest中。
下面介绍下工具类的功能
节点A:这个节点用于介绍工具类功能。
- streamModelLoader
- fileDescriptorModelLoader
modelClass---这个是你用什么类型请求图片。系统支持:String、Uri、File、Integer、URL、byte、自定义。(我们这里以String为例)
节点 A1和A2差不多所以只分析A1:
创建streamModelLoader:
这里下剧透其功能:帮助请求访问网络,其实现类为HttpUrlFetcher.
下面分析其具体的创建过程,这个比较重要,因为创建它的同时,也有很多类被创建,对后面读代码有很大的影响。
在进入buildStreamModelLoader,最终到达上图。发现其在创建streamModelLoader前先去创建Glide,
glide.get方法:
进入buider.createGlide():
节点F:下图创建sourceService、diskCacheService.
这里创建了serceService、diskCacheService、bitmapPool???
memoryCache---内存缓存。
disCacheFactory---创建磁盘缓存的工厂。
engine----驱动引擎。???
decodeFormat----设置的rgb
然后将上述放入new glide中
图1.0
图 2.0
上图是glide的内部创建的东西,不要太多。这里直接剧透,这些东西其实我们可以将其看成两张表单,这两张表单的作用:获取资源的转换对象。
先说下glide中不同的类型转换:
第一种表registry(图2.0)与网络有关的转换,由于我们会有不同类型的请求(String、Url、file等)会通过网络来拿到图片数据,此时图片数据的我们想用什么类型来接受尼。系统给了两种接受类型:inputStream与PracelFileDescriptor。默认为inputStream,其转换类为httpUrlFetcher,而PracelFileDescriptor对应的为null,估计是留给自己实现的。
第二张表:(图1.0)
dataLoadProviderRegistry.register表:将图片的缓存、网络等数据转换为bitmap、Gif、file等类型---俗称转码与解码。其转换类多就不细说。但是有一个共同的父类DataLoadProvider.
而streamModelLoader与fileDescriptorModelLoader属于第一张表的转换的类
streamModelLoader-----httpUrlFetcher(不同类型的请求,对应不同参数的httpUrlFetcher, 通过httpUrlFetcher网络访问获得InputStream类型的图片数据)
fileDescriptorModelLoader-----null
PracelFileDescriptor:操作文件流的工具类,详细问度娘。
上面我们分析了节点B 创建DraeableTypeRequest所需的类,接下来看其具体创建了些什么???
进入红色箭头
节点I:
从上图可以看到最后返回FixedLoadProvider,传入三个对象,modelLoader、transcoder、dataLoadProvider.
modelLoader---用于主要用于网络请求( streamModelLoader实现类httpUrlFethcer)
dataLoadProvider----用于图片的解码 (实现类ImageVideoGifDrawableLoadProvider)
transcoder-----用于图片转码。
FixedLoadProvider-----网络访问和转解码图片的总工具类
最后 将在DrawableTypeRequest 中创建的对象FixedLoadProvider传给GenericRequestBuider的loadProvider变量。这里我们顺便来了解下GenericRequestBuider:
这个类我们可以理解为一个请求的基本类。那么一个请求应该含有什么基本条件呢???我们可以看上图其构造函数。
需要context、modelClass(请求类型)、transcodeClass(GlideDrawable)、glide(操作类)、requsetTracker(请求队列)、lifecycle(周期回调函数)、LoadProvider(网络访问和转解码图片的总工具类)。
回到节点C
分析load()
将请求信息交给其父类(GenericRequestBuilder)保存。
为啥要给其父类????
小结:我们知道了对于一个请求而言,前期需要准备写什么???
- 系统需要单例创建glide,生成请求类型与图片类型对应的转换表单,创建工具类(一次)
- 对于一个请求来说,创建一个DrawableTypeRequest的类型抽象类。其持有
网络访问对象(streamModelLoader)、fileDescriptorModelLoader(null)、optionsApplier(暴露自己给开发者)。
- 将请求信息交给其父类GenericRequestBuilder保存。
体现类的多态性。
最后说下其关系:
GenericRequestBuilder(爷爷辈)--》BitmapRequsetBuilder、GifRequsetBuilder等父辈------》BitmapTypeRequest、GifTypeRequset等子辈------》DrawableTypeRequest
3. 完成请求:lnto()
glide.buildImageViewTarget的作用:
当我们的请求处理完成返回给我们bitmap,gif等类型的数据,我们如何让其适配我们的view呢?这个方法就是解决了。
简单不细讲。
进入GenericRequestBuilder .into
requsetTracker.runRequest
上面可以看出来开始处理请求了。requestsTracker存储请求的工具类。
(GenericRequest)request.begin(不解释,详情看前面链接)
onSizeReady()
节点:J
前面是设置宽高的省略了。从上图437行开始。
不知道你们是否还记得loadProvider的创建-------节点I
可以知道
loadProvider----FixedLoadProvider工具箱
modelLoader----ImageVideoModelLoader其持有httpUrlFetcher用于网络访问
dataFetcher---- ImageVideoFetcher ,其是ImageVideoModelLoader的内部类,完成具体的网络访问。
engine.load()
节点E:
上图:
149行:EngineKey----由于标识图片资源的。如身份证。
153行、162行通过EngineKey分别查询内存缓存和闪存是否有资源,找着任意一个都行。
闪存-----存储的是正在被用的图片。(Map<key,WeakReference>)
内存缓存-----近期被用到的图片,但现在没用到。(LruResourceCache)
180-186行 前面两个缓存都没找到,到达此处。我们就只能从磁盘缓存或者网络来拿到数据了, 由于二者都比较耗时,于是开启任务。
EngineJob-----劳动者(苦工)
DecodeJob-----转解码(工具)
EngineRunnable-------任务(事件)
我们就看到苦工拿着工具去处理任务了。
提下EngineJob的具有的功能:
this里面有6个参数,我们讲解下disCacheService、sourceService。其它参数是去设置其属性的,体现不了其功能。
节点H:
disCacheService、sourceService创建地方------节点F
从节点中看到这两个的具体实现类为线程池。
功能:
disCacheService-----提供1个线程执行任务,glide会用这些线程执行检查磁盘缓存的任务。
sourceService-------提供n个线程池执行任务,glide会用这些线程执行网络访问的任务(n与具体的CPU参数有关)
于是我们知道了EngineJob的工作提供检验磁盘缓存和网络访问的线程池(抽象理解为苦力)。
接下来我们进入EngineRunnable.run看看苦工是如何处理的。
节点D:用于回到上图EngineRunnable.run方法
没啥好说的,进入58行 decode()
这里有个if----isDecodingFromCache就是判断磁盘缓存中是否有任务需要的数据。
新创建的任务stage=CACHE。于是我们进入了decodeFromCache去磁盘找数据了。
108行和116行的方法中都是调用loadFromCache去磁盘中找数据,不同的是其传入的key不同,分别是resultKey(获取图片)和resultKey.getOriginalKey()(获取原始图片)。
下面说下磁盘缓存策略------由于我们对图片会有不同的设置(节点E:149行生成EngineKey的参数)都会导致key的值不同。
都会导致我们磁盘缓存。但是这样就有个问题了,曾经有一个Url,通过网络获得了图片,并磁盘缓存了。但是现在这个Url对应的图片,我想让其展示在一个更大的地方,那我们还需要在去网络访问吗???当然不用了。因为glide在拿到了网络中的原始图片后,会将原始图片在磁盘缓存中缓存一份。然后才会将图片转换为我们需要的图片。所以当我们下次在去访问时,发现是同一个url,直接从磁盘缓存中取然后转换为此时需要的图片类型,就不用再网络访问了。
所有新创建的请求(stage=CACHE)都会去检查磁盘缓存,不管是否有数据都会返回给回到节点D 58行。
下面说如果磁盘缓存没有要的数据,返回给我们为null时,从节点D中我们可以看到其执行了74行。
此时的isDecodingFromCache返回true。 于是我们改变了任务状态为SOURCE.并将认为交给manager.submitFromCache
发现是EngineRunnable的内部接口。其实现在EngineJob(苦工)中.
发现任务交接了sourceService。
由前面的节点H可以知道,sourceService为我们提供了线程去执行其任务。这样我们有回到节点D:用于回到上图EngineRunnable.run方法中执行decode()。
此时if中为false.
我们开始了网络访问分支。进入decodeFromSource
上图170行
Fetcher的创建---节点J
知道fetcher-----imageVideoFetcher
imageVideoFetcher.loadData()
有节点J知道streamFetcher-----httpUrlFetcher.这时我们终于到达了网络访问的具体实现类,同时也到达了终点站。
这只是一篇帮助文档。希望对你有帮助。。。