Android Glide 原理解析


另一个常用的图片库Picasso的解析,可以参考 这篇文章

一.提供的功能特性

  1. 使用默认的内存缓存和磁盘缓存(可自定义),并可以选择缓存使用策略,全局可以操作缓存

  2. glide提供了对bitmap对象的缓存、重用、回收特性,使内存更友好

  3. 可以加载网络资源、本地资源等,以及支持GIF图

  4. 可以为图片请求同时设置缩略图请求

  5. 可自定义图片的变换操作、解析格式、裁剪方式,resize大小等,包括缩放比例及自定义动画

  6. 可以设置加载成功失败的占位图及相应监听

  7. 可以暂停、恢复、取消加载,并与activity、fragment等生命周期相关联

二.简单使用

Glide.with(activity)//拿到界面对应的RequestManager对象
				.load(url)//load一个url
                .override(width, height)//重新裁剪大小
                .skipMemoryCache(true)//内存缓存策略(不读取也不存入内存)
				.diskCacheStrategy(DiskCacheStrategy.ALL)//磁盘缓存策略(存放图片的原文件和此次请求最终处理后的图片到本地缓存)
                .into(imageView);//显示到ImageView中

三.源码结构

1.内存缓存

(1)MemoryCache

在这里插入图片描述

  1. glide默认的内存缓存实现是LruResourceCache类,维护一个Lru规则的LinkedList存储key和结果

  2. glide的key是自定义的一个Key类对象,维护了一些信息作为key的实体,如url,width等

  3. 由于glide的结果支持多种类型而不是简单的Bitmap,所以Resource<?>类来封装,而map的value是对应的Resource对象

  4. 默认的缓存大小最大为堆内存的40%(正常由设备的长宽高及一些常量决定的);这里说的内存缓存包括对Resource的缓存以及bitmap的缓存(BitmapPool)

  5. 我们可以自己实现MemoryCache类来设置到Glide的全局环境中

(2)BitmapPool

在这里插入图片描述

  1. 在android3.0开始,bitmap对象像素数据存放在java堆内存中,再解码图片时,可以复用已有的未recycle的bitmap对象来节省内存,所以glide默认提供了LruBitmapPool类来进行bitmap的回收(3.0开始);

  2. 在android3.0~4.4中,bitmap的复用只支持像素数据大小相同的图片使用;4.4开始,支持了对于不同大小像素数据复用bitmap的功能;所以glide提供了两种策略(LruPoolStrategy类)进行对bitmap的缓存适配

  3. 我们可以自己实现BitmapPool来设置到Glide的全局环境中

(3)二级内存缓存

在这里插入图片描述在这里插入图片描述

  1. glide在内存缓存的策略上,使用了二级内存缓存+bitmap的缓存,大大提高了内存使用率;

  2. 二级内存缓存其中之一是一个LruResourceCache对象,就是常规认为的LinkedHashMap来维护的内存缓存,将Key-Resource对象进行保存,并在超过最大大小时按Lru策略释放;

  3. 二级内存缓存另一个是一个HashMap对象,叫做activeResources,其维护的是Key-WeakReference对象,顾名思义,它是用来存放当前正在被使用的资源的,且有多少存放多少,不会像一级缓存一样通过Lru策略限制大小,并且其value维护的是一个弱引用,不会影响其对象正常释放,这就体现出二级缓存的一个优势—提高了一定的命中率(如果认为当前使用的就有可能还会使用的话)

  4. 下面来看二级缓存另一个优势,也是实现二级缓存的主要原因:上面说过glide会使用一个LruBitmapPool来进行对bitmap的复用,那么这就有一个问题,就是如何确定哪些bitmap对象可以复用,尤其是针对正在使用的bitmap对象(只有一级缓存的话就有可能在cache中了),如果正在使用却被复用了岂不是出错了么?所以glide使用二级缓存将内存中的和正在使用的资源分离开来,这样,如上右图右半部分所示,当从内存缓存中移除时,就可以直接放入bitmapPool中了,因为内存中的肯定是没有在被使用的;而当bitmapPool中移除的时候就可以直接调用bitmap的recycle方法使其释放资源;

  5. 而资源什么时候应该放入cache或active中呢?如上图所示,在加载资源时会依次在cache和active中查找,如果在cache中找到了则要放入active中;如果是新加载的资源也会放入active中;在释放资源时,会先从active中移除资源,然后尝试放入cache中;这些流程就确保了active中的都是正在使用的资源,cache中的都是没有被使用的资源;

  6. 那么还剩最后一个问题,就是如何确认一个资源是否正在被使用呢?glide使用了引用计数法来标识,如上图,从active中获取的资源都会使其引用计数加一,而每次在资源的释放方法调用时该计数会减一,直到引用计数减为0时证明没有再被引用了,然后就可以将其放入cache了

2.磁盘缓存

在这里插入图片描述

  1. glide默认提供了DiskLruCache类作为磁盘缓存

  2. 磁盘缓存默认最大空间为250MB,路径为应用cache文件夹下的image_manager_disk_cache文件夹

  3. 磁盘缓存的key由一个SafeKeyGenerator对象根据原始的Key对象进行生成,有关glide的key的说明下面会单独说

  4. glide磁盘缓存的一大特点是可以双重缓存:就是资源的原始大小的缓存以及每次裁剪后的最终资源的缓存,这样一来当请求相同规则的资源时可以直接从磁盘缓存获取,而不需要加载出原始文件进行裁剪,也就是以空间换时间;这些缓存策略可以设置(DiskCacheStrategy);

  5. 我们也可以定义自己的DiskCache对象进行设置

3.图片对应的Key

这里简单说下图片在内存缓存和磁盘缓存中对应的key值的形式在这里插入图片描述

  1. Glide以一个EngineKey对象当作key,里面会存有真实的key(比如url等),还有一些其他请求参数,比如大小、转换等,重写其equals方法,当这些属性都一样时认为相等,所以这个EngineKey对象就可以作为result资源的key,从内存缓存或者result磁盘缓存读取时都以这个为key

  2. 而OriginalKey对象其实就存了EngineKey的真实key,并重写其equals方法,所以这个对象就可以作为source资源的key,从source磁盘缓存读取时就以这个为key

  3. 而写入磁盘缓存时,会将无论是EngineKey还是OriginalKey的字段通过SHA-256加密并转成16进制字符串当作名字存入本地

4.Glide对象

在这里插入图片描述

  1. 由图可知,Glide对象通过一个GlideBuilder类构建,也是全局单单例

  2. 虽然api提供了相关方法可以使我们自己创建并设置Glide对象(和picasso一样),但是glide已经不推荐这种方法,而是提供了一个GlideModule类,其两个接口方法提供了构建单例对象时的Builder和Glide对象供我们操作,我们只需要定义自己的GlideModule,并在manifest文件里进行的配置即可应用

  3. 比如我们想引进OkHttp作为网络加载库,在gradle文件里导入想过依赖后,就会发现多了一个OkHttpGlideModule类,其registerComponents方法里注册了OkHttp相关的组件,在使用网络请求时就会使用到这些组件了;有关glide提供的组件的概念下面会单独说,也是glide整个解析、加载、编码解码的框架设计核心

5.RequestManager—绑定生命周期

在这里插入图片描述
Glide的一大优势就是整个请求过程会绑定界面的生命周期

  1. 我们可以看到,Glide.with()方法的参数可以是activity、fragment等,这就意味着请求会绑定到界面上

  2. 每次调用with方法,Glide会根据参数类型从RequestManagerRetriever单例类中获取该参数对应的RequestManager对象,如下代码(以FragmentActivity为例)

public RequestManager get(FragmentActivity activity) {
    ...
    FragmentManager fm = activity.getSupportFragmentManager();//拿到FragmentManager
    return supportFragmentGet(activity, fm);
}
 
RequestManager supportFragmentGet(Context context, FragmentManager fm) {
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);//拿到FragmentManager对应的fragment
    RequestManager requestManager = current.getRequestManager();//拿到fragment对应的RequestManager
    if (requestManager == null) {//没有则新建
		//传入了fragment的lifecycleListener
        requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
        current.setRequestManager(requestManager);
    }
    return requestManager;
}
 
SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm) {
    SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);//拿到FragmentManager对应的fragment
    if (current == null) {//没有则建一个自定义的无界面fragment并加入FragmentManager用作关联生命周期
        current = pendingSupportRequestManagerFragments.get(fm);
        if (current == null) {
            current = new SupportRequestManagerFragment();
            pendingSupportRequestManagerFragments.put(fm, current);
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
            handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
        }
    }
    return current;
}
 
RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
        RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
    ...
    lifecycle.addListener(this);//将自己加入到fragment的lifecycleListener中,这样fragment的生命周期就会调用到此类中,完成请求的状态管理
}

由代码可知,每个activity会拥有一个RequestManager以及一个无界面的fragment在其中;

在fragment构建的时候会生成一个Lifecycle对象,其内部可以添加其他lifecycle对象;

在fragment的生命周期里会调用相应的lifecycle对象,内部就会调用加入的其他lifecycle对象的相应方法,而requestManager自身就是一个Lifecycle对象,加入到fragment时会添加到其lifecycle中,这样一来,相当于fragment的生命周期会调用到RequestManager的相应方法,RequestManager就可以管理请求的状态了
在这里插入图片描述

6.GenericRequestBuilder对象

在这里插入图片描述
在我们调用load(xxx)方法后,返回的是一个新的GenericRequestBuilder的子类对象,这个对象是包装各种请求参数用的,其相关方法为链式调用,其之所以是有继承结构是因为glide支持多种类型的资源,不同类型有着不同的XxxRequestBuilder构建类

  1. GenericRequestBuilder对象提供了各种占位图的设置方法、缓存策略的方法,裁剪大小、比例的方法,还提供了缩略图请求设置以及自定义动画的设置方法

  2. 其各个子类也有一些设置方法如裁剪方式等

  3. 在我们最终发起请求调用into()方法时,这个builder对象就会构建真正的GenericRequest对象(也有可能是缩略图请求对象),该对象保有着这些请求参数

7.Target对象

在这里插入图片描述

  1. 由图可知,Target类就是处理最终资源的类,其本身也是个LifecycleListener,可以绑定生命周期做操作;该接口提供了各种处理结果的方法;该接口的TranscodeTo泛型是为了支持多种类型的资源,后续会说到;

    在我们调用into()方法时,glide会根据transcodeTo的类型来创建不同的target

  2. 我们最常用的就是ImageView作为承载对象,对应生成的就是glide提供的ViewTarget的某一种,简单来说作用就是为imageView设置图片的处理

  3. 这里要说明的是,Glide的一大优势是默认自动获取imageView的大小进行最基本的资源裁剪,当然我们也可以自定义裁剪大小:在发起请求时,会先看是不是自己设置了裁剪大小,是则真正发起请求,不是则去获取ViewTarget的大小;ViewTarget大小如果已经可以取到,则真正发起请求,如果不可以,则会设置一个OnPreDrawListener到view上,当获取到了大小后通过回调通知,发起真正请求;
    在这里插入图片描述

8.RequestTracker对象

在这里插入图片描述

  1. RequestTracker对象其实就是管理一个界面request状态的一个类,有类图也可看出,在RequestManager对象创建出来时也会创建一个RequestTracker对象

  2. 一个界面的所有Request对象的begin、pause、cancel等都是由这个类进行的

9.Engine、EngineJob、EngineRunnable、DecodeJob对象

在这里插入图片描述
这几个类作为一个模块来讲,是因为他们几个联合起来完成了一次请求各个阶段的运行:由图知,在Request开始请求时,调用engine(在glide初始化时创建)的load()方法开始

(1)engine内部会先尝试从一级二级缓存中取出资源,如果有缓存则直接通过回调返回

(2)否则会创建一个EngineJob对象、一个EngineRunnable对象和一个DecodeJob对象,由EngineJob对象作为manager管理EngineRunnable的提交和回调等,代码如下

//EngineJob开启一个EngineRunnable
public void start(EngineRunnable engineRunnable) {
    this.engineRunnable = engineRunnable;
    future = diskCacheService.submit(engineRunnable);//使用diskCache的ExecutorService线程池进行处理
}
 
//EngineRunnable的run方法
public void run() {
    ...
        resource = decode();//加载数据
    ...
    if (resource == null) {
        onLoadFailed(exception);
    } else {
        onLoadComplete(resource);
    }
}
 
//EngineRunnable的decode方法
private Resource<?> decode() throws Exception {
    if (isDecodingFromCache()) {//当前状态是从DiskCache加载
        return decodeFromCache();
    } else {//当前状态是从数据源加载
        return decodeFromSource();
    }
}
 
//EngineRunnable获取资源失败
private void onLoadFailed(Exception e) {
    if (isDecodingFromCache()) {//当前为从DiskCache获取状态
        stage = Stage.SOURCE;//改为从数据源获取
        manager.submitForSource(this);//重新提交
    } else {
        manager.onException(e);
    }
}
 
//重新提交EngineRunnable
public void submitForSource(EngineRunnable runnable) {
    future = sourceService.submit(runnable);//使用source的ExecutorService线程池进行处理
}

由代码可知,EngineJob负责根据不同状态提交EngineRunnable对象,并接收回调,以此来管理着加载流程,这里可以看到glide是将从disk获取的任务和从数据源获取的任务分为两个线程池来进行,使得二者更好的协同工作,互不影响

(3)EngineRunnable对象内部负责从disk或者数据源取得数据的流程

//从diskCache获取
private Resource<?> decodeFromCache() throws Exception {
    Resource<?> result = null;
    result = decodeJob.decodeResultFromCache();
    if (result == null) {
        result = decodeJob.decodeSourceFromCache();
    }
    return result;
}
 
//从数据源获取
private Resource<?> decodeFromSource() throws Exception {
    return decodeJob.decodeFromSource();
}

由代码看出,从diskCache获取时,先去尝试获取result缓存(上面说到过的缓存结果的策略),如果没有则尝试获取source缓存(源文件),如果还没有则重新提交,去数据源获取数据,所有的这些步骤其实都是由DecodeJob完成的,下面我们来看看DecodeJob

(4)我们从流程图看下DecodeJob是如何从不同源获取数据并进行缓存的
在这里插入图片描述
我们可以看到,DecodeJob管理着从disk里取出result或者source资源的流程,以及从数据源获取数据的流程,其中从diskCache中获取的流程主要为:

  1. 通过key在DiskCache中找到result(Result缓存),有的话加载出来资源,转换成目标对象(transcode)进行返回;

  2. 如果没有Result缓存则从DiskCache里找到source(Source缓存),有的话加载出来资源,进行transformation转化为最终资源,再放入Result缓存,最后进行转换(transcode)并返回

从数据源获取的主要流程为:

  • 通过DataFetcher对象从数据源加载数据,加载出来资源后放入Source缓存,然后进行转化得到result,进行Result缓存,最终再进行转换并返回

以上的加载、转化、转换、放入缓存等操作使用到的DataFetcher、Transformation、Decoder、Encoder、Transcoder对象都来自于DataLoadProvider对象,这也是上面提到的glide实现多种类型资源的核心设计,下面就来好好看看这块是如何设计的!

10.DataLoadProvider组件

在这里插入图片描述

10.1数据处理的类型、阶段

对Glide而言,将数据处理分为了几个阶段,每个阶段都对应的不同的类型:

  1. 首先是我们的请求的"地址",这个地址可以是url、uri、file、resource资源等等,glide将其抽象为一个泛型,我在这里称其为Model,在我们调用load(xxx)方法时传入的参数,glide会根据其相应的类型做处理

  2. 有了Model,那么根据Model请求最终得到的数据源理论上也可以是很多类型,虽然大部分时候都是InputStream,glide也将其抽象为一个泛型,我在这里称其为DecodeFrom,因为处理数据时会将这个数据源编码成相应的数据对象,所以叫其DecodeFrom,意为将这个数据源编码到xxx

  3. 那么将DecodeFrom编码成的类型也会有多种,比如最简单的Bitmap,或者glide自己要处理的gif、GlideDrawable对象等等,所以将其也抽象为一个泛型,我在这里称其为DecodeTo

  4. 当得到DecodeTo类型的结果后,glide会对其做一次类型的转换,转换为glide最终处理需要的类型,这个过程叫做transcode转码,也被抽象为一个泛型,我在这里称其为TranscodeTo

  5. 综上所述,glide对于数据的处理流程大概如下图所示:
    在这里插入图片描述

10.2数据处理模型

有了上述处理流程和类型,glide其实是通过给每个阶段提供了相应类型(用泛型表示)的模型类实现不同阶段的处理,下面来看看这些模型类:

(1)ModelLoader< Model,DecodeFrom>+DataFetcher

首先第一步是从Model到DecodeFrom的流程,举个最简单的例子的话我们可以理解为从url到InputStream的过程,这一步glide提供的模型类是ModelLoader<Model,DecodeFrom>,由其泛型声明也可看出,这个类的作用是从Model转换到DecodeFrom的,其内部需要提供一个DataFetcher的类,用作真正的转换,由ModelLoader的方法getResourceFetcher(Model)可看出,ModelLoader会根据Model来返回一个DataFetcher的对象,该对象作用就是将Model转换为一个DecodeFrom;

而DataFetcher声明的方法loadData()的返回值看出,其返回的就应该是一个DecodeFrom类型的对象;

以上面类图为例,我们引入了OkHttp的库作为网络请求库,那么其就会向glide里注册一个OkHttpUrlLoader,可以看到其泛型是GlideUrl(Model)→InputStream(DecodeFrom),也就是会把我们的请求的地址作为一个GlideUrl转换为一个InputStream,其提供的OkHttpStreamFetcher也就会将这个glideUrl转换为InputStream,简单看下其代码就能大概明白什么意思了:

//ModelLoader
public class OkHttpUrlLoader implements ModelLoader<GlideUrl, InputStream> {
   ...
    @Override
    public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
        return new OkHttpStreamFetcher(client, model);//构建DataFetcher,传入Model(GlideUrl)
    }
}
 
//DataFetcher
public class OkHttpStreamFetcher implements DataFetcher<InputStream> {
    ...
    @Override
    public InputStream loadData(Priority priority) throws Exception {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url.toStringUrl());//通过url构建相应请求
		...
        Request request = requestBuilder.build();
        Response response = client.newCall(request).execute();
        responseBody = response.body();
        ...
        stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength);
        return stream;//返回InputStream
    }
}

而这些ModelLoader是如何注册到glide当中的我们在后面会另说

(2)ResourceDecoder< DecodeFrom,DecodeTo>

上述处理后,我们拿到了DecodeFrom了,假设是InputStream,那么需要将其解析成真正的资源对象,也就是DecodeTo类型,比如最简单的Bitmap,那么glide为这一过程提供的模型类就是ResourceDecoder,由其泛型声明和提供的decode方法可看出,作用是将DecodeFrom转换为DecodeTo,这里我们就拿最简单的InputStream转换为Bitmap的ResourceDecoder类来说:

//decode方法
@Override
public Resource<Bitmap> decode(InputStream source, int width, int height) {
    Bitmap bitmap = downsampler.decode(source, bitmapPool, width, height, decodeFormat);
    return BitmapResource.obtain(bitmap, bitmapPool);
}

这里需要提一下的是glide的结果类型都是Resource类对象,其实就可以理解为将xxx对象包装了一下,不同的Resource对象有一些特殊处理罢了,所以上面的类图的各种返回值都是Resouce对象,只是泛型不太一样,代表的是不同类型的资源;

StreamBitmap的decode方法,就是将InputStream(DecodeFrom)进行一系列的解析(decode、复用bitmap等)生成bitmap对象,最后又包了一下成为返回类型Resource<Bitmap(DecodeTo)>;

还有其他的一些ResourceDecoder用于其他类型的转换,下面也会提到

(3)Encoder< DecodeFrom>+ResourceEncoder

有了解码decode,相应的就要有encode—将不同的资源写入缓存中,于是glide设计了Encoder类,其泛型相对于自身功能来说可以声明为WrittenFrom,即从xxx写到xxx,其提供的方法encode的第二个参数为OutputStream对象,也就是说该类就是将WrittenFrom类型的资源写入到os中;

之所以这里叫WrittenFrom不叫DecodeFrom或者DecodeTo,是因为写入缓存有两种途径,一种是从数据源直接写入缓存(InputStream→OutputStream),一种是从现有资源写入缓存(Resource→OutputStream),后者其实是用于将转换后的最终资源(Result)写入缓存,所以对于后者来说,其WrittenFrom类型一定是Resource,于是glide提供了一个ResourceEncoder类,把泛型声明重写了一下,用于把资源写入缓存;

而从数据源直接写入缓存的就是Encoder了;

这里我们可以看个最简单的例子:将InputStream写入缓存的StreamEncoder

public class StreamEncoder implements Encoder<InputStream> {
    private static final String TAG = "StreamEncoder";

    @Override
    public boolean encode(InputStream data, OutputStream os) {
        byte[] buffer = ByteArrayPool.get().getBytes();
        try {
            int read;
            while ((read = data.read(buffer)) != -1) {//就是最基本的读写流操作
                    os.write(buffer, 0, read);
            }
            return true;
        ...
    }
}
(4)ResourceTranscoder< DecodeTo,TranscodeTo>

当我们生成Bitmap(DecodeTo)后,因为glide支持gif、bitmap等不同数据的操作,需要有不同的处理包装bitmap的类,所以glide提供了ResourceTranscoder类,来将DecodeTo类型转换为TranscodeTo类型,我们来看一个transcoder的例子:

//ResourceTranscoder
public class GlideBitmapDrawableTranscoder implements ResourceTranscoder<Bitmap, GlideBitmapDrawable> {
    private final Resources resources;
    private final BitmapPool bitmapPool;
    ...
    @Override
    public Resource<GlideBitmapDrawable> transcode(Resource<Bitmap> toTranscode) {
        GlideBitmapDrawable drawable = new GlideBitmapDrawable(resources, toTranscode.get());
        return new GlideBitmapDrawableResource(drawable, bitmapPool);
    }
}
//GlideBitmapDrawable
public class GlideBitmapDrawable extends GlideDrawable {
    ...
    GlideBitmapDrawable(Resources res, BitmapState state) {
        if (state == null) {
            throw new NullPointerException("BitmapState must not be null");
        }

        this.state = state;
        final int targetDensity;
        if (res != null) {
            final int density = res.getDisplayMetrics().densityDpi;
            targetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
            state.targetDensity = targetDensity;
        } else {
            targetDensity = state.targetDensity;
        }
        width = state.bitmap.getScaledWidth(targetDensity);
        height = state.bitmap.getScaledHeight(targetDensity);
    }
    ...
    @Override
    public void draw(Canvas canvas) {
        if (applyGravity) {
            Gravity.apply(BitmapState.GRAVITY, width, height, getBounds(), destRect);
            applyGravity = false;
        }
        canvas.drawBitmap(state.bitmap, null, destRect, state.paint);
    }
    ...
}
//GlideBitmapDrawableResource
public class GlideBitmapDrawableResource extends DrawableResource<GlideBitmapDrawable> {
    private final BitmapPool bitmapPool;

    public GlideBitmapDrawableResource(GlideBitmapDrawable drawable, BitmapPool bitmapPool) {
        super(drawable);
        this.bitmapPool = bitmapPool;
    }

    @Override
    public int getSize() {
        return Util.getBitmapByteSize(drawable.getBitmap());
    }

    @Override
    public void recycle() {
        bitmapPool.put(drawable.getBitmap());
    }
}

由代码可以看到,GlideBitmapDrawableTranscoder是将一个Resource对象转换为一个Resource对象;GlideBitmapDrawable对象其实就是包装了一个bitmap的GlideDrawable对象(Glide自定义绘制的Drawable对象);而生成的GlideBitmapDrawableResource对象就是包装了GlideBitmapDrawable对象的一个Resource对象,提供回收、获取size等Resource功能

(5)Transformation< DecodeTo>

在这里插入图片描述
这里再说下Transformation这个类,用过图片库的都知道,加载图片时我们可以设置其显示方式,比如centerCrop、fitCenter等,glide也可以,并将其抽象为Transformation类,其泛型也很好理解了,就是将一个Resource对象transformation一下,生成最终的一个Resource对象

(6)DataLoadProvider

在这里插入图片描述
现在,我们再来看下DataLoadProvider这个组件,他的泛型声明为DecodeFrom和DecodeTo,也就是说他是用来提供将数据源转换为数据的功能的;他的四个方法:

  • getCacheDecoder():返回的是一个从File转换为DecodeTo类型的ResourceDecoder对象,再结合其名字就不难理解其功能—提供从磁盘缓存转换到Bitmap(DecodeTo)的Decoder

  • getSourceDecoder():返回的是一个从DecodeFrom转换到DecodeTo的ResourceDecoder对象,与上面的相对应,就是提供了一个从InputStream转换到Bitmap的Decoder

  • getSourceEncoder():返回的是一个将DecodeFrom写入OutputStream的Encoder,即将数据源(InputStream)直接写入disk缓存的功能

  • getEncoder():返回的是一个将Resource资源直接写入缓存的ResourceEncoder,即将已有资源写入缓存的功能

所以,这个组件提供了缓存、数据源之间的读写功能

(7)LoadProvider

在这里插入图片描述
继承自DataLoadProvider的LoadProvider组件就是多支持了两个泛型Model和TranscodeTo,以及相应的组件ModelLoader和Transcoder

在一个GenericRequestBuilder对象构建时,glide就会根据类型等条件构建出LoadProvider,有了这个LoadProvider,就可以得到一次请求流程用到的所有相关组件了

//创建RequestBuilder时
DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
        ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
        RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) {
    super(context, modelClass,
            buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
                    GlideDrawable.class, null),
            glide, requestTracker, lifecycle);
    ...
}
//根据各种类型构建LoadProvider
private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
        ModelLoader<A, InputStream> streamModelLoader,
        ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
        Class<R> transcodedClass,
        ResourceTranscoder<Z, R> transcoder) {
    if (streamModelLoader == null && fileDescriptorModelLoader == null) {
        return null;
    }

    if (transcoder == null) {
        transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
    }
    DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
            resourceClass);
    ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
            fileDescriptorModelLoader);
    return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
}
(8)注册组件

上面我们说的这么多,那么这些所谓的组件都在什么时候有的呢,我们使用时也没发现有这些东西的存在呀,下面我们就来看看glide是在何时注册了这些组件以及如何使用的:

 Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
    ...
    loaderFactory = new GenericLoaderFactory(context);
	...
    dataLoadProviderRegistry = new DataLoadProviderRegistry();
	//注册各种glide默认提供的DataLoader
    StreamBitmapDataLoadProvider streamBitmapLoadProvider =
            new StreamBitmapDataLoadProvider(bitmapPool, decodeFormat);
    dataLoadProviderRegistry.register(InputStream.class, Bitmap.class, streamBitmapLoadProvider);
	...
    ImageVideoDataLoadProvider imageVideoDataLoadProvider =
            new ImageVideoDataLoadProvider(streamBitmapLoadProvider, fileDescriptorLoadProvider);
    dataLoadProviderRegistry.register(ImageVideoWrapper.class, Bitmap.class, imageVideoDataLoadProvider);
	...
	//注册各种glide默认提供的ModelLoader
    register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory());
    register(File.class, InputStream.class, new StreamFileLoader.Factory());
    ...
	//注册默认提供的transcoder
    transcoderRegistry.register(Bitmap.class, GlideBitmapDrawable.class,
            new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool));
    transcoderRegistry.register(GifBitmapWrapper.class, GlideDrawable.class,
            new GifBitmapWrapperDrawableTranscoder(
                    new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool)));
	//注册默认提供的transformation
    bitmapCenterCrop = new CenterCrop(bitmapPool);
    drawableCenterCrop = new GifBitmapWrapperTransformation(bitmapPool, bitmapCenterCrop);
    bitmapFitCenter = new FitCenter(bitmapPool);
    drawableFitCenter = new GifBitmapWrapperTransformation(bitmapPool, bitmapFitCenter);
}

由代码可以看出,在Glide单例对象创建时,会注册各种默认提供的组件,注册时用class对象来表示泛型,那么在构建request时,通过不同class对象进行get,就可以得到相应的组件了;

在每个DataLoader里面会生成其对应需要的Decoder、Encoder;

还可以看出,这些组件很多都是包装关系,及层层嵌套调用,每层完成自己的特殊处理,所以我们在实际中可以发现,一个简单的String为Model的请求生成的ModelLoader不是简单的String->InputStream这么简单,而是经过了一层层的包装,举个例子就是:你的String的Model生成的ModelLoader里会再生成一个以Uri为Model的ModelLoader,其里面又会生成一个以GlideUrl为Model的ModelLoader,这个ModelLoader才是我们最终处理用到的ModelLoader—也是OkHttp注册的GlideUrl→InputStream的ModelLoader;之所以要分这么多层也是为了把每个步骤抽象出来,比如String的ModelLoader里需要将String转换为Uri,再交由Uri的ModelLoader处理,Uri的ModelLoader需要判断uri是不是本地以及其schema等最终决定哪个DataFetcher,对其框架的扩展性极好;

其他几个组件也都是这样一层层包装下去的;

知道了这些组件的作用,我们就更加明确了glide加载流程了:
在这里插入图片描述

四.流程分析

以上把各个模块作用及实现做了简单分析,下面来看看glide整体的运行流程,将这些模块串联起来

我们就以主流程Glide.with(activity).load(url).into(imageView);来分析加载过程

note:详细的缓存加载与写入流程参考上面的模块讲解
在这里插入图片描述

  1. Glide.with(activity)拿到界面绑定的唯一RequestManager,使请求与声明周期绑定

  2. requestManager.load(url),根据请求参数的类型找到相应的ModelLoader等组件,构建LoadProvider,并创建出DrawableRequestBuilder对象

  3. into(ImageView),会根据设置或者ImageView的scaleType设置transformation,并根据transcode类型构建相应的Target对象,开始请求

  4. 请求时先将view上原有的request和资源清空(或回收或释放),然后根据设置的裁剪尺寸或view自身的尺寸开始请求流程

  5. 先依次从两级内存缓存中查找(根据策略),命中则回调通知,否则先到磁盘缓存里找

  6. 磁盘缓存依次寻找result和source资源(根据策略),命中后通过MainHandler回调到主线程,进行callback回调,没有命中则从数据源请求

  7. 通过modelLoader从数据源进行请求,并完成磁盘缓存,最终生成Resouce资源,通过MainHandler回调到主线程,进行callback回调

  8. ImageView的Target作为回调拿到Resource后,将Drawable设置到ImageView上完成加载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值