Glide源码小记

Glide 3.7源码阅读要点:

角色介绍:

Glide:对外暴露的统一接口,静态单利,内部成员众多,主要涉及缓存管理和请求管理
Request:抽象的请求接口,定义了一起加载操作相关的生命周期接口
RequestManager:请求管理器,同时是一个生命周期的监听者,其具备网络状态获取,请求管理(委托给RequestTracker实现),生命周期回调的能力
RequestTracker:请求跟踪器,只负责Request的保存和相关生命周期的分发
RequestManagerRetriever: 请求管理器的管理者(请求管理的猎犬),金静态单利,通过上下文信息返回不同的RequestManager
ModelLoader: model加载器,这里的model其实是对应一种输入类型,比如我想加载一个url对应的图片,这个string或者uri对应的类型就是一种model,该接口返回DataFetcher对象,真正的资源获取操作操作都在DataFetcher里
DataFetcher:处理数据获取的操作,比如从网上加载或者从本地目录,一般输出是InputStream
Encoder:数据的写入接口,比如将DataFetcher输出的InputStream写入到某个本地文件(StreamEncoder),一般在数据缓存时会用到这个接口
ResourceDecoder:这个接口对应原始数据类型转换为ViewTarget能使用的操作,比如将InputStream转换为Resource

1. 初始化流程

Glide对象创建
Glide对象的创建是延迟创建,单利对象,采用建造者模式的方式,此外还支持使用方参与其构建过程,我们可以在AndroidManifest文件中的meta-data中配置自定义的GlideModule类来参与。
glide对象
1.内部使用了两个线程池,都是使用的PriorityBlockingQueue阻塞队列和默认的拒绝策略
2.内存缓存也分为了两部分:bitmap缓存和其他内存缓存,其大小比列是4:2(你可以理解成大小分别为4张和2两张截图的大小),这里使用了MemorySizeCalculator这个对象来计算实际大小,该计算器会根据sdk版本和app所申请的实际内存大小来动态计算(实际就是sdk版本和activityManager.isLowRamDevice这个api)
3.diskCacheFactory是一个磁盘缓存工厂类,使用最近最少使用的缓存策略,默认大小是250mb,默认路径为/data/data//cache/image_manager_disk_cache
4.engine就是真正负责处理资源的类,其负责管理资源加载任务,回收资源等工作
Glide构造函数
在Glide的构造函数中,主要关注一下成员:
1.dataLoadProviderRegistry是一个数据加载器的提供者(这里的数据针对的是加载到内存的数据),负责提供不同数据类型数据加载器(不同数据类型之间转码或者数据压缩的工作),比如压缩bitmap等
2.loaderFactory是一个数据加载器工厂,负责提供各种数据加载器(ModelLoader实现者),这里的数据针对的是从磁盘或者在线下载的数据,比如给定一个url,输出一个inputStream。可以看到默认注册了很多的加载器
3.transcoderRegistry中注册了资源转换的转换器,比如将bitmap转换成drawable类型等

  1. 简单流程
Glide.with(applicationContext).load(url).diskCacheStrategy(DiskCacheStrategy.ALL).into(imageView);

上述是我们使用Glide加载一个网络图片的最简单的使用案例,接下来看一下这个最简单的流程源码实现:
1.Glide.with方法由多个重载方法实现,最终都是调用到RequestManagerRetriever的get方法,该方法会根据上下文类型返回不同的RequestManager,这里我使用Application,则会返回包含ApplicationLifecycle的RequestManager实例
RequestManagerRetriever.get
2.RequestManager.load方法也是一个重载的方法,不同的参数类型对应不同的资源加载,我这里是一个String类型的url.这里直接进入fromString方法,最终会转到loadGeneric方法上
RequestManager.load
loadGeneric
loadGeneric方法中主要是获取了相关的modelLoader,最后再返回一个DrawableTypeRequest对象,这里streamModelLoader的实际类型是StreamStringLoader(其真正使用的是HttpUrlGlideUrlLoader类型对象,该对象可以返回HttpUrlFetcher实例,负责做真正的数据获取工作),fileDescriptorModelLoader的实际类型是FileDescriptorStringLoader。
load
返回DrawableTypeRequest之后开始初始化相关的成员参数,load方法的实现如上,这里的ModelType就是我们之前的String类型,model就是url
diskCacheStrategy()
上述方法是缓存模式的设置,glide中支持四种:
缓存模式
DiskCacheStrategy.NONE:表示不缓存
DiskCacheStrategy.SOURCE:表示仅缓存源资源,这里的源资源就是从从网上或者文件中加载到的原始InputStream资源
DiskCacheStrategy.RESULT:表示仅缓存处理(比如资源压缩/尺寸裁剪)之后的资源,不保留原始资源
DiskCacheStrategy.ALL:表示既缓存原始资源,又缓存处理之后的资源
接下来就是into方法的流程了,如图:
GenericRequestBuilder中的into方法
可以看到这里先检验了是否在主线程,标志着该方法只能在主线程调用,之后会检查目标View是否为空,之后会检查该ImageView是否设置了ScaleType,如果设置了,则需要处理图片,我这里都没有设置,最后会调用into的重载方法,传入的参数是GlideDrawableImageViewTarget类型的对象(可以从ImageViewTargetFactory这个工厂类看到具体的类型匹配)
into
上图是into的一个重载方法,传进来的参数target就是GlideDrawableImageViewTarget类型的对象,这里直接看target.getRequest,该方法返回一个Request实例,可以看到其实现就是调用的View.getTag或者View.getTag(tagId);也就是说使用Glide加载图片的View是不能自己调用setTag方法的,
getRequest方法的实现
回到into方法内部,原则上来讲,如果是第一次作为ViewTarget,previous变量为空,如果不是第一次,则会返回之前绑定的request(GenericRequest类型)实例,所以这里先回收了之前的request,之后开始创建本次Request实例并设置相关的成员变量,Request对象的创建是用了对象缓存池,其数据结构是ArrayDeque,之后将request对象和ViewTarget绑定关系,然后将request对象给requestTracker(专职的request生命周期跟踪者),该对象会缓存请求,并调用请求对象的begin方法,开始请求流程
request.begin
begin这个方法先改变request的状态为WAITING_FOR_SIZE,之后检查宽高是否可用,我没有设置过,所以会调用target.getSize来计算宽高,实际上就是获取View的宽高,获取成功之后会调用onSizeReady方法,之后会给targetView设置一个默认加载前的图片
尺寸准备好了
onsizeReady方法先检查并设置了请求的status,之后获取了相关的modelLoader,这里是一个ImageVideoModelLoader实例,之后通过modelLoader获取了一个dataFetcher,这是一个ImageVideoFetcher实例,其中之前的streamLoader(StreamUriLoader类型)和fileDescriptorLoader,实际上最后从网络上加载的操作是委托给了HttpUrlFetcher。之后是获取了资源转换器(GifBitmapWrapperDrawableTranscoder类型),开始进入engine的加载数据环节
engine.load
engine是资源获取的中枢控制器,这里的load方法做了如下事情:
1.针对资源生成了唯一的Key,后续从内存读取缓存资源的key值
2.首先从内存中加载缓存的资源,这里的内存缓存就是我们之前提到的memoryCache(MemoryCache接口的实现者,这里的是LruResourceCache实例),如果命中内存缓存,就调用onRourceReady告诉监听者,这里的监听者就是之前的request对象,这里需要说明一下,当命中缓存后,engine会将命中的资源数据存储到一个hashmap中,表示该资源正在被使用。也就是说glide的内存缓存大小不等于其计算的bitmap池和memoryCache的和
3.如果没有命中缓存,则会尝试从正在使用的hashmap中再去查找一下
4.如果还是没有命中,则先检测是否该资源正在加载的过程中,若是则等他其加载之后的回调,结束本次加载,避免重复
5.如果当前需要的资源没有加载过,则新建EngineJob和相关的DecodeJob,并包装到EngineRunnable中,开始从磁盘或者网络中进行资源加载,从这里开始,后续的操作都在线程池里了,EngineRunnable对象的run方法会直接调用decode方法:
加载数据的入口方法
decode方法首先会判断是否从本地缓存文件中去获取,默认第一次都是先尝试加载本地缓存文件,如果本地缓存文件没有,则会去下载,相关方法如下:
获取本地缓存文件
加载本地缓存的经过处理的数据文件
加载文件
这里的diskCacheProvider是InternalCacheDiskCacheFactory类型的对象,这里首先会获取缓存目录下指定的结果缓存文件(即非原始数据的缓存文件),如果存在则执行decode操作,可以理解为资源类型的转换操作。如果没有获取到非原始的缓存,则会尝试获取原始数据缓存文件;如果获取成功,则本次结束
接着看下从网络获取的流程:
从网络获取
decodeSource方法是入口函数,首先使用fetcher去加载数据,这里实际就是上文提到的HttpUrlFetcher对象,其loadData方法的本质就是使用HttpURLConnection去获取inputStream,decodeSource获取到inputStream之后,调用decodeFromSourceData方法,这个方法会判断是否需要缓存原始数据流,如果需要,则会缓存到本地文件(cacheAndDecodeSourceData方法),之后再从本地将数据加载返回。如果不需要,则直接进行数据的类型转换操作(decode),并返回相关数据给engineJob(调用onResourceReady),然后engineJob发消息给主线程,通知进行ui层面的数据填充。这样一个完整的流程就走完了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值