这篇文章将会为大家梳理一下Glide3.5版本的基本流程,为了方便阅读,文章中的源码部分将省略部分有关异常捕获与日志相关代码。
使用示例
首先依照惯例,先来一个最简单的例子:
1 | Glide.with(context).load(path).into(imageView); |
非常简洁的一句代码,下面我们按照这个调用的流程一步步的来进行分析。
1.Glide.with(Context context)
1 | public static RequestManager with(Context context) { |
这个方法很好理解,其中RequestManagerRetriever.get()方法的作用为获得RequestManagerRetriever的单例对象,然后调用其中的get方法获得RequestManager对象。
其中RequestManager类实现了LifecycleListener接口,主要作用是根据Fragment或Activity的生命周期来调用onStart,onStop,onDestroy方法,以此控制请求的开启,停止与重启。
RequestManagerRetriever.get(Context context)
RequestManagerRetriever中,get方法的数量很多但是逻辑上都是大同小异,先放上代码:
1 | //下面会省略部分异常判断的代码 |
在上述方法中可以看到,这些方法的作用为根据传入的Context类型的不同调用不同方法构造不同的RequestManager对象。
需要注意的是:其中如果传入的Context为Application或该方法不在主线程中执行,则会返回Application级别的RequestManager单例对象,也就是说图片的加载不会与Activity或Fragment的生命周期绑定。
RequestManagerRetriever.supportFragmentGet(Context context, FragmentManager fm)
RequestManagerRetriever.fragmentGet(Context context, android.app.FragmentManager fm)
RequestManagerRetriever.getApplicationManager(Context context)
由于这三个方法可以归到一类里,所以就在这里一起分析
1 | private RequestManager getApplicationManager(Context context) { |
上面这部分就是Glide能够绑定生命周期的关键代码了,通过上述代码可以发现,Glide中会在Activity或Fragment中添加一个不可见的Fragment,这个Fragment对象中会持有Lifecycle的对象。因为Activity与其内部的Fragment的生命周期是绑定的,所以在Activity执行生命周期的方法时,Glide中对应的Fragment也会进行相应的生命周期,这样就相当于实现了对Activity生命周期的监听。
还有其中的RequestManagerTreeNode类,可以通过这个类获取到RequestManagerFragment对象下属的所有子RequestManagerFragment以达到统一控制其生命周期的效果。
2.RequestManager.load(T model)
1 | public <T> DrawableTypeRequest<T> load(T model) { |
这个方法也只有短短的一行,其中getSafeClass(T model)方法作用是返回传入参数的Class对象,下文就不再赘述了
RequestManager.loadGeneric(Class modelClass)
1 | private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) { |
DrawableTypeRequest.load(T model)
1 | //DrawableTypeRequest.load(T model) |
通过代码可以看到,虽然该方法名字叫做load,但是方法中只是将传入的model保存了下来,而真正的加载,则是在into()方法中进行的。
3.DrawableRequestBuilder.into(ImageView view)
1 | //DrawableRequestBuilder.into(ImageView view) |
Glide.buildImageViewTarget(ImageView imageView, Class transcodedClass)
1 | //Glide.buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) |
上述代码中出现的三个Target类负责将加载出的图片在ImageView中展示出来,并且由于Target类继承LifecycleListener接口,可以看出也正是Target类负责执行对于其所绑定的Activity或Fragment的生命周期的监听。
GenericRequestBuilder.into(T target)
1 | //省略部分异常捕获代码 |
经过前面漫长的准备工作,终于在这个方法中正式开始了图片的请求。
RequestTracker.runRequest(Request request)
1 | //RequestTracker.runRequest(Request request) |
GenericRequest.begin()
1 | public void begin() { |
在target.getSize(this)这句语句中传入的回调方法,将在控件的ViewTreeObserver.OnPreDrawListener方法中,也就是控件即将绘制时调用。
GenericRequest.onSizeReady(int width, int height)
1 | public void onSizeReady(int width, int height) { |
Engine.load(Key signature, int width, int height, DataFetcher fetcher,DataLoadProvider loadProvider, Transformation transformation, ResourceTranscoder transcoder,Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb)
1 | public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher, |
其中可以发现Glide中使用了二级的内存缓存,其中第一级为LRU缓存(最近最少使用),第二级为Active缓存,如果一张图片在LRU缓存中已经不存在了,但是依然在其他地方被使用着,那么就会去直接使用那一张图片。
EngineRunnable.run()
1 | public void run() { |
EngineRunnable.decode()
1 | private Resource<?> decode() throws Exception { |
在上面的decodeFromCache方法中,就是Glide缓存策略的第二层,也就是磁盘缓存,而磁盘缓存又分为两种,一是由源地址所获取的图片原文件,二是经过转换后的图片文件。Glide一大特点即为能够根据控件大小的不同对图片尺寸进行处理后再加载,而这处理后的图片文件也会被保存入缓存中,而且在图片加载时优先级会更高于原图。
而且由上面的代码能看出,不论是由缓存加载,还是由数据源加载,实际都是交由DecodeJob来进行处理的。
DecodeJob.decodeFromSource()
1 | public Resource<Z> decodeFromSource() throws Exception { |
DecodeJob.decodeSource()
1 | private Resource<T> decodeSource() throws Exception { |
DecodeJob.decodeFromSourceData(A data)
1 | //如果缓存策略为磁盘缓存,则会先将图片加载至磁盘缓存中,再由磁盘缓存中取出使用 |
DecodeJob.transformEncodeAndTranscode(Resource decoded)
1 | private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) { |
在该方法在返回成功后,会将其作为参数调用onLoadComplete方法。
EngineRunnable.onLoadComplete(Resource resource)
1 | //EngineRunnable.onLoadComplete |
由于上面这几个方法的调用逻辑很清晰,所以就姑且写在一起了,上面的流程为onLoadComplete作为回调方法被调用,随后将传入的Resource参数使用Handler传给主线程处理,主线程根据message来调用加载成功或失败的方法。
GenericRequest.onResourceReady(Resource<?> resource, R result)
1 | private void onResourceReady(Resource<?> resource, R result) { |
至这个方法为止,一个最简单的图片加载流程就算是基本结束了。
小结
本篇文章简单的梳理了Glide加载图片的基本流程,没有想到Glide如此简单易用的外表下,内部的逻辑竟然如此的复杂与庞大,不得不说,Glide源代码的复杂程度超出了我的预期,其中引入的抽象概念与泛型的大量使用也给阅读也带来了不小的困难,碍于本人水平有限,文章中难免有错误与疏漏之处,欢迎大家来批评指正。