描述
版本
源码基于4.12.0
implementation 'com.github.bumptech.glide:glide:4.12.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'
### glide使用
```kotlin
Glide.with(context)
.load(url)
.into(imageView);
源码
主流程分别是with、load、into这三个方法,我们重点分析一下
源码类图
在参考文章上找到了一张很棒的类图
重要的方法和类
RequestManager
RequestBuilder
这里可以这么看: 如果泛型类型是Bitmap,则会生成一个BitmapImageViewTarget 如果泛型类型是Drawable,则会生成一个DrawableImageViewTarget 这里的泛型对应的就是RequestBuilder.transcodeClass属性
with方法
- Glide.with重载参数
Glide的with方法可以使用如下图中的参数加载图片,所以我们可以知道Glide可以使用ApplicationContext、Activity、Fragment、View作为参数获取RequestManager
- Glide.with
- Glide.getRetriever方法获取RequestManagerRetriever
这里查看getRetriever和get方法
RequestManagerRetriever用来获取管理RequestManager,
get方法有五个重载方法,其中除了参数Context外,其它的都是使用Fragment实现的。
Glide.with方法获取RequestManager方法
RequestManagerRetriever类的五个get方法后面讲解
小结
with方法内部会创建一个全局静态的glide对象
with方法主要的目的是返回一个RequestManager,并且with有五个重载方法,重载参数可以是Context、Fragment、ACtivity、View、FragmentActivity。最终会使用RequestManagerFactory.build方法创建RequestManager对象。
下面我们对with的几个重载参数进行一下说明,
- Activity:使用FragmentManager添加一个非v4的Fragment,然后调用fragmentGet方法,fragmentGet方法内部会创建RequestManager,并将RequestManager赋值给RequestManagerFragment,最后返回RequestManager。
- Fragment :使用Fragment添加一个子Fragment来实现,逻辑同1
- FragmentActivity:同1,不过添加的Fragment是v4的Fragment
- View:获取ApplicationContext,然后调用getApplicationManager来获取RequestManager,这种方式获取的RequestManager是不会管理Activity生命周期的
- Context:Context类型与1、2、3、4中哪个类型匹配就使用哪个类型来获取
load方法
- RequestManager.load方法
load方法也有多个参数的重载方法,方法返回RequestBuilder对象
- RequestManager.asDrawable和RequestManager.load方法
- 查看asDrawable
asDrawable可以使用Drawable展示,还有几个方法asBitmap、asFile、asGif他们可以支持不同类型的图片加载
- RequestManager.as方法
这个as方法如下,返回一个RequestBuilder对象。
- 上面获取RequuestBuilder.asDrawable还会调用load(url)方法
我们发现load方法到这里将url也就是loadGeneric方法的参数model赋值给了RequestBuilder.model
小结
RequestManager.load方法主要是用来决定我们要加载资源的类型,例如可能加载的是File、Bitmap、Drawable、Gif,然后生成一个RequestBuilder,并且将请求的url赋值给RequestBuilder.model。
into方法
非常长的方法
- RequestBuilder.into方法
这个tartet是在Glide中调用buildImageViewTarget方法生成的: glideContext.buildImageViewTarget(view, transcodeClass)
- 重载调用
下面的target.setRequest方法最终将我们的request作为tag设置给了target内部持有的View,其实就是以前搞ListView的时候的view.setTag
- RequestManager.track
- 重点看第三步RequestTracker.runRequest方法
- Request.begin方法
我们主要看SingleRequest.begin方法
- 在SingleRequest.onSizeReady方法内部会使用engine加载图片
- Engine.load方法
后面的的方法使用waitForExistingOrStartNewJob加载图片资源
- waitForExistingOrStartNewJob方法
engineJob.start(decodeJob);下图中这个方法是用来执行线程池获取图片资源的
- 实现线程池执行任务
- 线程池执行任务DecodeJob的run方法
- DecodeJob.runWrapped方法
第二章图是getNextGenerator的代码说明
这里的getNextGenerator方法需要看一下 ** 这里是及其重要的分支逻辑**
getNextState方法也需要看一下,这里是及其重要的分支逻辑
- DecodeJob.runGenerators
顺便说一句,11中的几个方法配合这里的runGenerators不就是和okhttp一样的责任链模式吗,又是天下大同。
- DecodeJob.reschedule
如果方法走到这里说明需要去网络去请求数据,请求完成后Glide会把数据存储到磁盘中,这个过程很耗时Glide的做法是不继续等待数据返回。而是调用reschedule,reschedule会重新把DecodeJob添加到线程池中进行调度,这样如果请求成功将数据存放到磁盘的话,那么我们下一次线程池再调度到我们的DecodeJob的时候就会成功从磁盘缓存中获取到数据同步返回。(个人感觉这里的逻辑是Glide里面最精妙的了,我看懂的时候拍着大腿直呼过瘾)
- DecodeJob.decodeFromRetrievedData方法从磁盘中获取图片数据
- 主流程结束
分支流程
Glide如何加载内存资源
Enging.loadFromMemory
内存缓存的源码要从Engine.load方法开始
- Engine.load
下图说明EngineKey如何唯一的标识某一个图片资源key的
- Engine.loadFromMemory方法加载内存缓存数据
后面我们会分别查看loadFromActiveResources和loadFromCache方法
- loadFromActiveResources和loadFromCache两个方法分析
- loadFromActiveResources从正在请求的资源中查找图片资源
- loadFromCache方法
重点看getEngineResourceFromCache方法
到了Glide,对LruCache上层又做了一次继承,所以最终真实类型是LruResourceCache
Glide是如何去磁盘中加载缓存的
看ResourceCacheGenerator、DataCacheGenerator这两个类,磁盘缓存加载策略是在DecodeJob.getNextGenerator方法中进行的。
ResourceCacheGenerator
- ResourceCacheGenerator
- ResourceCacheGenerator.onDataReady
- 查看DecodeJob.onDataFetcherReady
DataCacheGenerator
DataCacheGenerator用于获取原始的图片数据,处理逻辑和ResourceCacheGenerator相似
Glide如何对原始数据进行转换存储
DataCacheGenerator类中处理
Glide是如何去调用网络获取数据的
暂时猜测是从DataUrlLoader类中获取的
Glide中的线程池是怎么调度的
总结
Glide可以实现生命周期绑定的操作,如果我们的请求是在activity或fragment中请求图片的,则会使用添加fragemtn的方式让我们的请求绑定成功生命周期(理解不了的是,为什么到了现在glide仍然没有向Lifecycle转换的想法)。最终会生成一个RequestManager用来处理请求。
绑定生命周期结束后,则对url进行保存,同时可以决定我们加载的图片类型,例如:Bitmap、Drawable、File。
最后是请求的加载逻辑,首先glide会尝试去内存中获取图片数据,如果获取成功那么直接返回。如果没有获取到内存图片数据,那么会使用线程池进行数据加载。在线程池中执行的加载请求会有一个责任链的逻辑,会依次尝试获取磁盘中的被转换过的图片数据、磁盘中的原始原始图片数、去网络获取数据。需要说明的是如果去网络获取数据是不会马上返回结果的,而是直接返回null,但是他会重复多次将我们的请求加入到线程池等待执行,直到请求成功后存储到磁盘,然后从磁盘中返回glide图片数据。
图片加载框架做了什么
- 线程切换
- 内存缓存和磁盘缓存处理
- 防oom的处理
- 列表加载图片图片错乱的问题