> 文章列表 > 源码:Glide

源码:Glide

源码:Glide

一、使用

implementation 'com.github.bumptech.glide:glide:4.9.0'
Glide.with(activity) //context.load("xxx.jpeg")  //url链接、地址.into(iv)  //View控件

二、源码分析

Glide采用链式调用,分为三个主要流程 with、load、into

1.with

一个重载方法,在with方法中可以传入Activity或者Fragment,一定要与生命周期关联

public static RequestManager with(@NonNull FragmentActivity activity) {return getRetriever(activity).get(activity);
}
    @NonNullprivate static RequestManagerRetriever getRetriever(@Nullable Context context) {Preconditions.checkNotNull(context, "You cannot start a load on a not yet attached View or a Fragment where getActivity() returns null (which usually occurs when getActivity() is called before the Fragment is attached or after the Fragment is destroyed).");//通过get方法创建Glide实例return get(context).getRequestManagerRetriever();}

Glide的创建

getRetriever方法最终返回了一个RequestManagerRetriever对象

    @NonNullpublic static Glide get(@NonNull Context context) {if (glide == null) {Class var1 = Glide.class;synchronized(Glide.class) {if (glide == null) {checkAndInitializeGlide(context);}}}return glide;}
  • new一个Glide对象:build构建者模式

  • 创建了一个空Fragment:绑定生命周期实现了Lifecycle接口

  • 把生命周期方法传导出去

2.load

构建RequestBuilder对象,把Url传进去

3.into

  • engine.load中三级缓存(EngineKey)

    • 活动缓存(Hashmap)(弱引用缓存)

    • 内存缓存(Lru算法)

    • 磁盘缓存(Lru算法)

  • 从主线程切换到子线程去请求网络数据

  • 切回主线程

  • 主线程渲染数据

  • 图片裁剪,自适应

三、Glide使用的缓存

内存-磁盘-网络的三级缓存

先到内存中查找图片,找到了就直接显示内存图片,没找到就去磁盘中查找图片,在磁盘中找到就直接显示磁盘图片,最后没找到的话再去请求网络。

默认开启三级缓存机制

  1. 活动缓存(ActiveResources):在某个Activity范围,页面退出该缓存就不存在,分担内存缓存的负担
  2. 内存缓存(LruCache)某个App范围,应用完全退出就不存在,加快数据读取
  3. 磁盘缓存(DiskLruCache)整个系统,只要不删除数据,就一直存在,永久性保存

1.内存缓存

        内存缓存默认开启,如需关闭需调用  .skipMemoryCache(true)

  • Glide自己定义的一种缓存,本质就是hashMap,弱引用,用一次就缓存,以后需要就直接拿,不需要就清除
  • 内存缓存LruCache是系统自身管理的
  • 图片缓存不会同时存在活动缓存和内存缓存的

弱引用缓存(活动缓存)

private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {if (!isMemoryCacheable) {return null;}//从ActiveResources中获取资源EngineResource<?> active = activeResources.get(key);if (active != null) {//当前资源被引用了 +1active.acquire();}return active;}final class ActiveResources {//HashMap 中 储存了弱引用资源final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();}

总的流程是首先从弱引用缓存中取,再去从内存中去取

active.acquire(); 资源引用+1

        主要统计当前资源被多少个地方引用/使用,被引用了+1,这时候资源都存在弱引用集合,不引用就-1,直到引用数为0,就将资源从弱引用存入到内存LruCache

内存缓存LruCache

private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {if (!isMemoryCacheable) {return null;}//内部调用remove方法,返回当前资源并且将其从内存LruCache中移除EngineResource<?> cached = getEngineResourceFromCache(key);if (cached != null) {//资源被引用+1cached.acquire();//将当前资源加入到 弱引用集合activeResources.activate(key, cached);}return cached;
}

如果从内存LruCache中找到资源后,内存中就将该资源移除了,转而加入到弱引用集合中了

总结:

  • 弱引用集合存的是当前正在使用的资源,重复利用
  • 内存LruCache存的则是之前使用过但当前不使用的资源
  • 整体内存缓存是为了防止同一张图片资源重复加入内存

2.磁盘缓存

磁盘缓存

可以调整缓存策略,默认AUTOMATIC

.diskCacheStrategy(DiskCacheStrategy.ALL)

  • ALL:远程图片资源使用 DATA 和 RESOURCE 缓存,本地图片只使用 RESOURCE 缓存;
  • NONE:不使用缓存;
  • DATA:将检索到的原始图片资源写入磁盘缓存;
  • RESOURCE:将检索到的原始图片资源解码之后再写入磁盘缓存;
  • AUTOMATIC:根据数据源智能选择策略,数据源可以是:DataFetcher、EncodeStrategy、ResourceEncoder; 

磁盘缓存本质是本地文件缓存,为了解决普通文件读取效率不高的问题,Glide使用了DiskLruCache框架进行数据保存和读取,对图片进行了加密和压缩处理

三级缓存读取顺序为:弱引用缓存 -> LruCache -> DiskLruCache。

四、架构设计

1.资源加载设计

相比于Glide来说,Fresco侵入性太强,扩展性也没有Glide强

bitmap并没有着眼于bitmap,进行了高度抽象,不仅仅是一个图片加载框架,而是一个资源从不同形态之间相互转换的框架,没有对输入类型做任何限制,比如url、uri、File、资源id、视频等等,都统一抽象成Request

问题:不同的Request如何管理加载

        针对每一种Request,都有对应的ModelLoader

        当一个Request请求时,遍历所有的ModelLoader,通过handlers()判断这ModelLoader能否处理这个Request,想要增加一种Request,只要开发对应的ModelLoader即可

问题:怎么实现真正的加载请求

       同一种Request有很多加载方式,如从网络加载、从磁盘加载等,非常复杂,这里独立出DataFetcher,不同的方式对应一个不同的DataFetcher,两者职责分离

        LoadData只是对DataFetcher的一层包装

总结:

        根据传入的请求具体类型,通过遍历所有的ModelLoader判断该ModelLoader能否处理这种请求,然后用该ModelLoader中的DataFetcher去具体加载这个请求。

2.解码转码设计

有了ModelLoader和DataFetcher机制,Glide可以方便的将不同的原始请求加载到内存中了,这个时候的数据还是二进制 Data,携带了格式数据,需要进行编码过程,去除原始的格式信息,然后拿到原始信息进行重新编码,将其转化为不同格式,解码以及转码之后的数据称为Resource

问题:解码,转码的格式是不固定的,如何高效的解码转码?

        从Registry中获取所有的ResourceDecoder和ResourceTranscoder,判断哪个解码器或转码器适合当前格式,然后调用相关的decode和transcode方法

        跟Request被加载的过程类似,采用模板方法模式

3.资源变化设计

资源解码并转码之后,需要做一些特殊需求,如:圆角、透明度等,使用Transformation,这个是可选的,需要在构建这整个流程的时候指定Transformation

Transformation

        BitmapTransformation

                CenterCrop

                CenterInside

                CicleCrop

                FltCenter

                Rotate

                RoundedCorners

4.资源显示设计

将符合条件的Resource显示在指定的Target上