android源码宇宙-Glide

842

描述

版本

源码基于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这三个方法,我们重点分析一下

源码类图

在参考文章上找到了一张很棒的类图
image.png

重要的方法和类

RequestManager

image.png

RequestBuilder

这里可以这么看: 如果泛型类型是Bitmap,则会生成一个BitmapImageViewTarget 如果泛型类型是Drawable,则会生成一个DrawableImageViewTarget 这里的泛型对应的就是RequestBuilder.transcodeClass属性

image.png

with方法

  1. Glide.with重载参数

Glide的with方法可以使用如下图中的参数加载图片,所以我们可以知道Glide可以使用ApplicationContext、Activity、Fragment、View作为参数获取RequestManager

image.png

  1. Glide.with

image.png

  1. Glide.getRetriever方法获取RequestManagerRetriever

这里查看getRetriever和get方法

RequestManagerRetriever用来获取管理RequestManager,

image.png
get方法有五个重载方法,其中除了参数Context外,其它的都是使用Fragment实现的。
image.png

Glide.with方法获取RequestManager方法

RequestManagerRetriever类的五个get方法后面讲解

小结

with方法内部会创建一个全局静态的glide对象
with方法主要的目的是返回一个RequestManager,并且with有五个重载方法,重载参数可以是Context、Fragment、ACtivity、View、FragmentActivity。最终会使用RequestManagerFactory.build方法创建RequestManager对象。

下面我们对with的几个重载参数进行一下说明,

  1. Activity:使用FragmentManager添加一个非v4的Fragment,然后调用fragmentGet方法,fragmentGet方法内部会创建RequestManager,并将RequestManager赋值给RequestManagerFragment,最后返回RequestManager。
  2. Fragment :使用Fragment添加一个子Fragment来实现,逻辑同1
  3. FragmentActivity:同1,不过添加的Fragment是v4的Fragment
  4. View:获取ApplicationContext,然后调用getApplicationManager来获取RequestManager,这种方式获取的RequestManager是不会管理Activity生命周期的
  5. Context:Context类型与1、2、3、4中哪个类型匹配就使用哪个类型来获取

load方法

  1. RequestManager.load方法

load方法也有多个参数的重载方法,方法返回RequestBuilder对象
image.png

  1. RequestManager.asDrawable和RequestManager.load方法

image.png

  1. 查看asDrawable

asDrawable可以使用Drawable展示,还有几个方法asBitmap、asFile、asGif他们可以支持不同类型的图片加载

image.png

  1. RequestManager.as方法

这个as方法如下,返回一个RequestBuilder对象。
image.png

  1. 上面获取RequuestBuilder.asDrawable还会调用load(url)方法

image.png
我们发现load方法到这里将url也就是loadGeneric方法的参数model赋值给了RequestBuilder.model
image.png

小结

RequestManager.load方法主要是用来决定我们要加载资源的类型,例如可能加载的是File、Bitmap、Drawable、Gif,然后生成一个RequestBuilder,并且将请求的url赋值给RequestBuilder.model。

into方法

非常长的方法

  1. RequestBuilder.into方法

这个tartet是在Glide中调用buildImageViewTarget方法生成的: glideContext.buildImageViewTarget(view, transcodeClass)

image.png

  1. 重载调用

image.png

下面的target.setRequest方法最终将我们的request作为tag设置给了target内部持有的View,其实就是以前搞ListView的时候的view.setTag

image.png
image.png

  1. RequestManager.track

image.png

  1. 重点看第三步RequestTracker.runRequest方法

image.png

  1. Request.begin方法

我们主要看SingleRequest.begin方法
image.png
image.png

  1. 在SingleRequest.onSizeReady方法内部会使用engine加载图片

image.png
image.png

  1. Engine.load方法

后面的的方法使用waitForExistingOrStartNewJob加载图片资源

image.png

  1. waitForExistingOrStartNewJob方法

engineJob.start(decodeJob);下图中这个方法是用来执行线程池获取图片资源的

image.png
image.png

  1. 实现线程池执行任务

image.png

  1. 线程池执行任务DecodeJob的run方法

image.png

  1. DecodeJob.runWrapped方法

第二章图是getNextGenerator的代码说明

image.png

这里的getNextGenerator方法需要看一下 ** 这里是及其重要的分支逻辑**

image.png

getNextState方法也需要看一下,这里是及其重要的分支逻辑

image.png

  1. DecodeJob.runGenerators

顺便说一句,11中的几个方法配合这里的runGenerators不就是和okhttp一样的责任链模式吗,又是天下大同。

image.png

  1. DecodeJob.reschedule

如果方法走到这里说明需要去网络去请求数据,请求完成后Glide会把数据存储到磁盘中,这个过程很耗时Glide的做法是不继续等待数据返回。而是调用reschedule,reschedule会重新把DecodeJob添加到线程池中进行调度,这样如果请求成功将数据存放到磁盘的话,那么我们下一次线程池再调度到我们的DecodeJob的时候就会成功从磁盘缓存中获取到数据同步返回。(个人感觉这里的逻辑是Glide里面最精妙的了,我看懂的时候拍着大腿直呼过瘾)
image.png
image.png

  1. DecodeJob.decodeFromRetrievedData方法从磁盘中获取图片数据

image.png

  1. 主流程结束

分支流程

Glide如何加载内存资源

Enging.loadFromMemory
内存缓存的源码要从Engine.load方法开始

  1. Engine.load

image.png
下图说明EngineKey如何唯一的标识某一个图片资源key的
image.png

  1. Engine.loadFromMemory方法加载内存缓存数据

后面我们会分别查看loadFromActiveResources和loadFromCache方法

image.png

  1. loadFromActiveResources和loadFromCache两个方法分析
  • loadFromActiveResources从正在请求的资源中查找图片资源

image.png
image.png

  • loadFromCache方法

image.png
重点看getEngineResourceFromCache方法

到了Glide,对LruCache上层又做了一次继承,所以最终真实类型是LruResourceCache

image.png

Glide是如何去磁盘中加载缓存的

看ResourceCacheGenerator、DataCacheGenerator这两个类,磁盘缓存加载策略是在DecodeJob.getNextGenerator方法中进行的。

ResourceCacheGenerator
  1. ResourceCacheGenerator

image.png
image.png
image.png

  1. ResourceCacheGenerator.onDataReady

image.png

  1. 查看DecodeJob.onDataFetcherReady

image.png

DataCacheGenerator

DataCacheGenerator用于获取原始的图片数据,处理逻辑和ResourceCacheGenerator相似

Glide如何对原始数据进行转换存储

DataCacheGenerator类中处理

Glide是如何去调用网络获取数据的

暂时猜测是从DataUrlLoader类中获取的

Glide中的线程池是怎么调度的

总结

Glide可以实现生命周期绑定的操作,如果我们的请求是在activity或fragment中请求图片的,则会使用添加fragemtn的方式让我们的请求绑定成功生命周期(理解不了的是,为什么到了现在glide仍然没有向Lifecycle转换的想法)。最终会生成一个RequestManager用来处理请求。
绑定生命周期结束后,则对url进行保存,同时可以决定我们加载的图片类型,例如:Bitmap、Drawable、File。
最后是请求的加载逻辑,首先glide会尝试去内存中获取图片数据,如果获取成功那么直接返回。如果没有获取到内存图片数据,那么会使用线程池进行数据加载。在线程池中执行的加载请求会有一个责任链的逻辑,会依次尝试获取磁盘中的被转换过的图片数据、磁盘中的原始原始图片数、去网络获取数据。需要说明的是如果去网络获取数据是不会马上返回结果的,而是直接返回null,但是他会重复多次将我们的请求加入到线程池等待执行,直到请求成功后存储到磁盘,然后从磁盘中返回glide图片数据。

图片加载框架做了什么

  1. 线程切换
  2. 内存缓存和磁盘缓存处理
  3. 防oom的处理
  4. 列表加载图片图片错乱的问题