Glide全面详解

Glide全面理解

基本流程

with

  1. 判断context是否是Application
  2. 如果是的话,就不做判断,图片加载到程序崩溃才会取消
  3. 否则的话,会给当前Activity添加一个Fragment来监听其生命周期,来及时取消掉图片加载
  4. return 得到RequestManager对象(包含着对Glide的初始化)

ps:非主线程context会直接被当做是Application的context来使用

load

  1. fromUrl -> loadGeneric
  2. Glide.buildStreamModelLoader(modelClass, context);Glide.buildFileDescriptorModelLoader(modelClass, context); 获取到ModelLoader对象来加载图片
  3. 将上面的东西作为参数获取到DrawableTypeRequest对象,主要提供asBitmapasGif这两个方法,分别又创建了一个BitmapTypeRequestGifTypeRequest,如果没有进行强制指定的话,那默认就是使用DrawableTypeRequest
  4. 真正的load方法是在DrawableTypeRequest的父类DrawableRequestBuilder里面,这里面也是大多数我们常用的API了
  5. load方法还是返回DrawableTypeRequest,然后我们再来看into()这个方法

into

into()方法也是整个Glide图片加载流程中逻辑最复杂的地方

  1. 来看GenericRequestBuilder类中的into()
  2. 调用了glide.buildImageViewTarget()构建Target对像来最终显示图片
  3. 追溯到buildTarget(),如果调用了asBitmap()就会去到BitmapImageViewTarget对象,否则一般都是GlideDrawableImageViewTarget对象,DrawableImageViewTarget对象暂且不管
  4. 回到into(),看到Request request = buildRequest(target);requestTracker.runRequest(request); 这两个核心方法,Request是用来发出加载图片请求的关键组件

requestTracker.runRequest(request) -> GenericRequest.begin() -> onSizeReady()

buildRequest()

调用obtainRequest -> GenericRequestobtain方法把全部参数组装起来,构建出request对象进行返回

requestTracker.runRequest(request);

  • requestTracker.runRequest() : 调用GenericRequest.begin() ->
    • 占位图原理:当图片为null就最终去调用setErrorPlaceholder,而在开始的时候他就会调用target.onLoadStarted()并传入占位图,这就是占位图的原理。
    • 具体图片加载:当指定了图片大小则调用onSizeReady() , 否则调用target.getSize() 然后内部会根据ImageView计算宽高,最终还是会地调用onSizeReady()
onSizeReady
  1. onSizeReady() :
    • 对于loadProvider.getModelLoader()需要回到DrawableTypeRequest的构造方法中,看到了调用了一个buildProvider()方法,并把streamModelLoaderfileDescriptorModelLoader等参数传入到这个方法中,这两个ModelLoader就是之前在loadGeneric()方法中构建出来的。
    • buildProvidrer() :
      • 调用了glide.buildTranscoder() : 构建出ResourceTranscoder用于对图片转码,实际是构建出GifBitmapWrapperDrawableTranscoder对象
      • 调用glide.buildDataProvider() ; 构建出DataLoadProvider用于对图片编解码,实际构建出ImageVideoGifDrawableLoadProvider对象
      • new ImageVideoModelLoader() : 把之前loadGeneric()的两个ModelLoader封装到ImageVideoModelLoader当中
      • 最后一步,new FixedLoadProvider 把上面三个东西都封装进去,也就是onSizeReadyloadProvider对象了
    • 所以loadProvider.getModelLoader()loadProvider.getTranscoder()得到的就是刚刚的ImageVideoModelLoaderGifBitmapWrapperDrawableTranscoder
    • ImageVideoModelLoader.getResourceFetcher: 调用streamLoader.getResourceFetcher()方法获取一个DataFetcher,(streamLoader其实就是loadGeneric()中构建的StreamStringLoader),获取到HttpUrlFetcher,并且new ImageVideoFetcher对象并传入HttpUrlFetcher,最后得到一个ImageVideoFetcher作为返回
    • 将刚刚的诸多对象参数一同传入engine.load()
  2. engine.load()
    • EngineJob engineJob = engineJobFactory.build();: 获取EngineJob 用于开启线程,为异步加载图片做准备
    • new DecodeJob : 十分复杂后面详解
    • EngineRunnable.run() ; 调用decode() -> decodeFromSource -> DecodeJob.decodeFromSource()
  3. DecodeJob.decodeFromSource()
    decodeSource()获得一个Resource对象,然后调用transformEncodeAndTranscode()方法来处理这个Resource对象。

    • decodeSource() : 调用onSizeReady()得到的ImageVideoFetcher.loadData()
      • 调用刚刚HttpUrlFetcher.loadData(): 这里就是网络通信层,获取到InputStream并返回回去,并且封装到new ImageVideoWrapper()当中返回
      • decodeFromSourceData(data); : 这个data就是返回回来的ImageVideoWrapper, 使用在onSizeReady得到的FixedLoadProvider.getSourceDecoder(GifBitmapWrapperResourceDecoder对象)decode方法来对图片进行解码
  4. GifBitmapWrapperResourceDecoder.decode()
    实际是调用decodeStream(),会先从流中读取2个字节的数据,来判断这张图是GIF图还是普通的静图,如果是GIF图就调用decodeGifWrapper()来进行解码,如果是普通的静图就用调用decodeBitmapWrapper()来进行解码

  • decodeBitmapWrapper() : 调用bitmapDecoder.decode(),这个bitmapDecoder是一个ImageVideoBitmapDecoder对象
  • bitmapDecoder.decode() : 调用source.getStream()来获取到服务器返回的InputStream,调用streamDecoder.decode()进行解码,streamDecode是一个StreamBitmapDecoder对象。然后再去调用Downsampler.decode()
  • Downsampler.decode() : 这个方法就是图片加载、压缩、旋转、圆角等处理并返回需要显示的Bitmap对象,这里面调用BitmapResource.obtain()将Bitmap封装成Resource<Bitmap>并返回

至此返回Resource<Bitmap>对象,我们继续看new GifBitmapWrapper(bitmapResource, null)作为封装返回,一直返回到GifBitmapWrapperResourceDecoder.decode()里面看到我们把GifBitmapWrapper作为参数做二次封装new GifBitmapWrapperResource()

回到DecodeJob里面的decodeFromSourceData,通过loadProvider获取到了Resource<GifBitmapWrapper> 对象

至此decodeResource方法已经为我们从网络中获取到图片资源
下面我们就看transformEncodeAndTranscode(decoded)又做了什么

  1. transformEncodeAndTranscode()
    看到Resource<Z> result = transcode(transformed); -> transcoder.transcode(transformed) ,这个 transcoder就是那个DrawableTypeRequest对象,它的构建函数中去构建了一个FixedLoadProvider对象,然后我们将三个参数传入到了FixedLoadProvider当中,其中就有一个GifBitmapWrapperDrawableTranscoder对象,onSizeReady()中获取到这个参数,并传递到了Engine,然后传递到DecodeJob
  • GifBitmapWrapperDrawableTranscoder : 用于转码,调用transcode()Resource<GifBitmapWrapper>中取出GifBitmapWrapper对象,然后再从GifBitmapWrapper中取出Resource<Bitmap>对象
    • 如果Resource<Bitmap>为空说明是gif,就调用getGifResource()获取图片即可
    • 否则需要再做一次转码把Bitmap转换成drawable对象,因为Glide是使用GifDrawable来加载动图,需要保持静图和动图的类型一致
  • bitmapDrawableResourceTranscoder.transcode(bitmapResource) : 再做一次转码,把Resource<Bitmap>对象封装成Resource<GlideBitmapDrawable> 对象,因为静态图GlideBitmapDrawable和动态图的GifDrawable都是GlideDrawable的子类,所以使用Resource<GlideDrawable>作为返回

  1. EngineRunable.run
    一层一层返回回到EngineRunable.decode()方法中,接下来就是吧decode()返回的Resource<GlideDrawable>作为参数,调用onLoadComplete(resource);,里面是调用Engine.load()里面的EngineJobonResourceReady(),这里面就是处理图片处理完成的回调
  • 回调:就是在Engine.load()里面的addCallback,往上追在onSizeReady里面engine.load()传入this,也就是GenericRequest本身自己实现了onResourceReady()

  • onResourceReady() ; 就是把资源提取出来然后调用target.onResourceReady(result, animation),这个target 就是在into()作为参数glide.buildImageViewTarget()返回的GlideDrawableImageViewTarget对象(这个在很早之前分析过)

  1. GlideDrawableImageViewTarget
    onResourceReady : 这里最终把资源丢到setResource()里面,再由view.setImageDrawable(resource); ,终于大功告成了!!!

缓存

Glide缓存分为内存缓存和硬盘缓存两块,内存缓存的主要作用是防止应用重复将图片数据读取到内存当中,而硬盘缓存的主要作用是防止应用重复从网络或其他地方重复下载和读取数据。

缓存KEY

缓存KEY在engine.load()中进行,然后在fetcher.getId()根据资源url生成id,然后在keyFactory.buildKey()连同图片宽高等等的一系列参数一起创建出一个独一无二的KEY

内存缓存

LruCache算法(Least Recently Used),也叫近期最少使用算法。它的主要算法原理就是把最近使用的对象用强引用存储在LinkedHashMap中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。

Glide内存缓存的实现自然也是使用的LruCache算法。不过除了LruCache算法之外,Glide还结合了一种弱引用的机制,共同完成了内存缓存功能

缓存对象准备

  1. load() -> loadGeneric() -> Glide.buildStreamModelLoader() -> Glide.get(context).getLoaderFactory().buildModelLoader()
  2. Glide.get() -> GlideBuilder.createGlide() -> memoryCache = new LruResourceCache(calculator.getMemoryCacheSize()); : 这里就是Glide使用的内存缓存,可以进去看一下也不难,实现了LruCahce算法

实际工作

  1. 缓存读取:Engine.load()方法当中的loadFromCache()loadFromActiveResources() :从LruResourceCache中获取到缓存图片之后会将它从缓存中移除,然后将这个缓存图片存储到activeResources当中。activeResources就是一个弱引用的HashMap,用来缓存正在使用中的图片,loadFromActiveResources()方法就是从activeResources这个HashMap当中取值的。使用activeResources来缓存正在使用中的图片,可以保护这些图片不会被LruCache算法回收掉。
  2. 缓存写入:EngineJob.handleResultOnMainThread() : 通过EngineResourceFactory构建出了资源对象EngineResource,回调EngineonEngineJobComplete(),然后就把资源放入到activeResources里面了。
  3. activeResources 是以弱引用缓存着正在使用的图片资源,LruCache 是缓存着没有在使用的图片资源。图片被使用就调用engineResource.acquire()表示图片被使用数量+1,没有使用就调用engineResource.release()表示图片使用数量-1。当图片引用数==0的时候,可以看到engineResource.release()里面的listener.onResourceReleased(),就是把资源从activeResources中删除,然后添加到lruCache中保存下来

硬盘缓存

Glide自己编写了DiskLruCache,但是原理是和Google那个差不多

硬盘缓存读取

  1. Engine.load() -> EngineRunnable.run() -> EngineRunnable.decode() -> EngineRunnable.decodeFromeCache() : 调用decodeJob.decodeResultFromCache()decodeJob.decodeSourceFromCache() ,这两个参数的区别就在设置的DiskCacheStrategy.RESULTDiskCacheStrategy.SOURCE
  2. decodeJob.decodeResultFromCache() : 直接loadFromCache()然后transcode()返回,之前分析过了
  3. decodeJob.decodeSourceFromCache() : 因为是获取原始图片,所以key不需要这么多参数,所以调用了getOriginalKey, 然后transformEncodeAndTranscode()返回,之前也分析过了
  4. loadFromCache() ; 实际就是调用自己的DiskLruCache获取缓存文件

硬盘缓存写入

  1. 原始图片缓存写入: Engine.load() -> EngineRunnable.run() -> EngineRunnable.decode() -> EngineRunnable.decodeFromSource() -> EngineRunable.decodeSource() -> decodeJob.decodeFromSource() -> decodeJob.decodeSource() -> decodeJob.decodeFromSourceData() -> decodeJob.cacheAndDecodeSourceData() : 然后就把原始图片写入到缓存了
  2. 转换图片缓存的写入: Engine.load() -> EngineRunnable.run() -> EngineRunnable.decode() -> EngineRunnable.decodeFromSource() -> EngineRunable.decodeSource() -> decodeJob.decodeFromSource() -> decodeJob.transformEncodeAndTranscode() -> decodeJob.writeTransformedToCache() : 把转换后的图片写入到缓存

炒鸡简单有木有!!

高级用法

场景:当图片是相同的,token保存在url当中使得url动态改变,那么如何来动态适配这个key呢

分析:Engine.load() -> fetcher.getId() :其实就是之前构建HttpUrlFetcher传入的url地址,-> glideUrl.getCacheKey() : 只是单纯的判断返回url,所以我们可以通过重写``GlideUrl这个类的getCacheKey()`来实现去除token的缓存图片

解决方法:

//MyGlideUrl继承GlideUrl,然后重写getCacheKey()就可以了
//因为传入自定义的GlideUrl,所以Glide是不会包装,而直接使用我们自己的

Glide.with(this)
     .load(new MyGlideUrl(url))
     .into(imageView);

回调与监听

基本源码: into -> glide.buildImageViewTarget() -> imageViewTargetFactory.buildTarget() : 在这里构建的target就是最后回调使用的target对象了,也就是target.onResourceReady()这个方法。(详细追溯可以看会之前的记录)

自定义Target

into方法除了imageView以外,还有传入Target作为参数的,也就是我们可以自定义Target来实现自己的资源回调监听。

Target接口有很多实现,主要关注ViewTargetSimpleTarget 来实现重写就可以了

  • SimpleTarget ; 相当简单,确定泛型指定返回资源的类型,指定GlideDrawable就是万金油,确定不是gif图,指定bitmap也没问题。
  • ViewTarget : 同样简单,需要指定传入的View和返回的资源类型,然后傻瓜一般的步骤,实现自己需要的高度自定义功能

preload

我们想提前加载图片,可以使用preload提前将资源下载到缓存里面,当然我们可以自定义target自己实现,看自己的选择吧。

//从网络预加载资源到缓存
Glide.with(this)
     .load(url)
     .diskCacheStrategy(DiskCacheStrategy.SOURCE)
     .preload();

//真正投放资源到ImageView
Glide.with(this)
     .load(url)
     .diskCacheStrategy(DiskCacheStrategy.SOURCE)
     .into(imageView);

preload()的源码非常简单,本事就是加载图片什么都不做的一个SimpleTarget而已,随便追追就可以了。

downloadOnly

  • downloadOnly(int width, int height) : 用于在子线程中下载图片

代码如下,整个过程需要在子线程中执行否则会报错,target.get()是一个阻塞的方法,直到拿到了资源才会返回

  FutureTarget<File> target = Glide.with(context).load(url).downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
                final File imageFile = target.get();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(context, imageFile.getPath(), Toast.LENGTH_LONG).show();
                    }
                });

源码解析:
downloadOnly() -> GenericTranscodeRequest.downloadOnly(int width,int height) -> GenericRequestBuilder.into() -> new RequestFutureTarget() : 真正的逻辑就在我们调用get()的时候,他们去获取资源当onResourceReady()触发以后resultReceived=true,所以才会停止阻塞,然后把资源返回。(因为阻塞,所以必须在子线程中执行)

  • downloadOnly(T target) : 用于在主线程中现在图片

需要自己实现Target接口,大部分的方法都是请求图片资源的生命周期相关的,最重要实现getSize()onResourceReady()
回想之前getSize() 就是最终调用onSizeReady(),这里我们只需要返回原始大小就够了

 @Override
    public void getSize(SizeReadyCallback cb) {
        cb.onSizeReady(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
    }

onResourceReady() 当中就可以直接获取到我们需要的数据了,相当简单,然后把自定义的target传入downloadOnly就可以了(可以在主线程中运行,因为内部已经帮我们切换线程回来了)

listen

就是在target之前的一个监听拦截,具体使用如下

//return false表示事件继续向下,return true表示事件已消费,那么就不会执行target.onResourceReady()

  Glide.with(this).load(url).listener(new RequestListener<String, GlideDrawable>() {
                @Override
                public boolean onException(Exception e, String model, Target<GlideDrawable> target,
                    boolean isFirstResource) {
                    return false;
                }

                @Override
                public boolean onResourceReady(GlideDrawable resource, String model,
                    Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                    return false;
                }
            })
            .into(imageView);

源码解析:
into() -> buildRequest() -> buildRequestRecursive() -> obtainRequest() -> GenericRequest.obtain() : 就是参数都传进去GenericRequest对象里面,然后看到GenericRequest.onResourceReady()GenericRequest.onException() 就可以看到listner的监听和拦截了

相当简单

图片变换转换

源码解析:
1. transformation的管理与保存
bitmapTransform() -> DrawableRequestBuilder.transform() -> GenericRequestBuilder.transform() : GenericRequest构造器,如果只传入一个自定义transformation, 那么transformation就等于此,否则多个transformation 就会作为参数一并传入MultiTransformation

MultiTransformationtransform()就是遍历调用传进来的transhformation的集合。

  1. transform()的调用
    GenericRequest.onSizeReady() -> engine.load() : 传入了之前初始化好的transformation对象,然后传入到了DecodeJob
    DecodeJob发挥作用是在EngineRunable内,无论是decodeJob.decodeFromSource()decodeJob.decodeSourceFromCache()最终都是调用decodeJob.transformEncodeAndTranscode() -> decodeJob.transform() : 这里就是调用了前面传进来的transformation.transform() : 并接受返回

流程至此圆满结束

API使用:
继承BitmapTransform,自定义实现
这个时候就要丢出轮子

  /**
     * 每个Transformation的标识ID
     * 一般以本类名称即可
     *
     * @return
     */
    @Override
    public String getId() {
        return getClass().getName();
    }

   /**
     * @param pool        服用Bitmap的缓冲池
     * @param toTransform 需要变换的图片
     * @param outWidth    图像的宽
     * @param outHeight   图像的高
     * @return
     */
    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        return circleCrop(pool, toTransform);
    }

自定义模块

基本使用

构建自定义的Module

public class MyGlideModule implements GlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
    }
}

Manifest文件中配置(因为glide是通过扫描Manifest获取module配置的)

 <application>

        <meta-data
            android:name="com.rayhahah.glide.MyGlideModule"
            android:value="GlideModule" />

        ...

    </application>

源码解析

主要在Glide.get()方法当中,Glide的初始化是在with()的时候RequestManager里面初始化的。
Glide.get() :
- List<GlideModule> modules = new ManifestParser(applicationContext).parse(); : 这个方法就是扫描Manifest文件获取自定义的module配置
- 遍历调用module.applyOptions() : 自定义让builder.set...
- bulider.createGlide() : 这里初始化,如果不为空,就是我们设置了新的配置项,他就不会自动创建了
- module.registerComponents():加入替换Glide的组件的逻辑

配置项修改

Glidebuilder的配置项修改:
- setMemoryCache() : 用于配置Glide的内存缓存策略,默认配置是LruResourceCache。
- setBitmapPool() : 用于配置Glide的Bitmap缓存池,默认配置是LruBitmapPool。
- setDiskCache() : 用于配置Glide的硬盘缓存策略,默认配置是InternalCacheDiskCacheFactory。
- setDiskCacheService() : 用于配置Glide读取缓存中图片的异步执行器,默认配置是FifoPriorityThreadPoolExecutor,也就是先入先出原则。
- setResizeService() : 用于配置Glide读取非缓存中图片的异步执行器,默认配置也是FifoPriorityThreadPoolExecutor。
- setDecodeFormat(): 用于配置Glide加载图片的解码模式,默认配置是RGB_565。

ExternalCacheDiskCacheFactory : 就是把原本缓存写入私有目录,现在写入到SD卡里面,是Glide帮我们内置的缓存工厂
Glide默认是RGB_565,当然我们可以设置成ARGB_8888,图片质量会变好,但是内存开销也会变大

···
public static final int DISK_CACHE_SIZE = 500 * 1024 * 1024;

@Override
public void applyOptions(Context context, GlideBuilder builder) {
    builder.setDiskCache(new ExternalCacheDiskCacheFactory(context,dirName,DISK_CACHE_SIZE));
    builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
}

@Override
public void registerComponents(Context context, Glide glide) {

}

···

动态修改Glide组件

大部分组件不需要我们修改,但是Glide网络链接使用的是HttpUrlConnection,我们可以替换成常用的OKHttp3。

先看看Glide构造方法中组件的数量吧(很多很厉害,很牛逼)

   Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
        ...

        register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory());
        register(File.class, InputStream.class, new StreamFileLoader.Factory());
        register(int.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
        register(int.class, InputStream.class, new StreamResourceLoader.Factory());
        register(Integer.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
        register(Integer.class, InputStream.class, new StreamResourceLoader.Factory());
        register(String.class, ParcelFileDescriptor.class, new FileDescriptorStringLoader.Factory());
        register(String.class, InputStream.class, new StreamStringLoader.Factory());
        register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory());
        register(Uri.class, InputStream.class, new StreamUriLoader.Factory());
        register(URL.class, InputStream.class, new StreamUrlLoader.Factory());
        register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
        register(byte[].class, InputStream.class, new StreamByteArrayLoader.Factory());

        ...
    }

register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());这句代码就表示,我们可以使用Glide.with(context).load(new GlideUrl("url...")).into(imageView)的方式来加载图片,所以我们需要替换的就是HttpUrlGlideUrlLoader.Factory()

查看内部,发现就是HttpUrlGlideUrlLoaderHttpUrlFetcher 这两个类在工作,照着抄并且替换成OkHttp3的网络请求代码得到如下

照着HttpUrlFetcher形成的OkHttpFetcher

public class OkHttpFetcher implements DataFetcher<InputStream> {

    private final OkHttpClient client;
    private final GlideUrl url;
    private InputStream stream;
    private ResponseBody responseBody;
    private volatile boolean isCancelled;

    public OkHttpFetcher(OkHttpClient client, GlideUrl url) {
        this.client = client;
        this.url = url;
    }

    @Override
    public InputStream loadData(Priority priority) throws Exception {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url.toStringUrl());
        for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) {
            String key = headerEntry.getKey();
            requestBuilder.addHeader(key, headerEntry.getValue());
        }
        requestBuilder.addHeader("httplib", "OkHttp");
        Request request = requestBuilder.build();
        if (isCancelled) {
            return null;
        }
        Response response = client.newCall(request).execute();
        responseBody = response.body();
        if (!response.isSuccessful() || responseBody == null) {
            throw new IOException("Request failed with code: " + response.code());
        }
        stream = ContentLengthInputStream.obtain(responseBody.byteStream(),
                responseBody.contentLength());
        return stream;
    }

    @Override
    public void cleanup() {
        try {
            if (stream != null) {
                stream.close();
            }
            if (responseBody != null) {
                responseBody.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getId() {
        return url.getCacheKey();
    }

    @Override
    public void cancel() {
        isCancelled = true;
    }
}

照着HttpUrlGlideUrlLoader形成的OkHttpGlideUrlLoader

public class OkHttpGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {

    private OkHttpClient okHttpClient;

    public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {

        private OkHttpClient client;

        public Factory() {
        }

        public Factory(OkHttpClient client) {
            this.client = client;
        }

        private synchronized OkHttpClient getOkHttpClient() {
            if (client == null) {
                client = new OkHttpClient();
            }
            return client;
        }

        @Override
        public ModelLoader<GlideUrl, InputStream> build(Context context, GenericLoaderFactory factories) {
            return new OkHttpGlideUrlLoader(getOkHttpClient());
        }

        @Override
        public void teardown() {
        }
    }

    public OkHttpGlideUrlLoader(OkHttpClient client) {
        this.okHttpClient = client;
    }

    @Override
    public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
        return new OkHttpFetcher(okHttpClient, model);
    }
}

最后动态注册一下组件就可以啦

public class MyGlideModule implements GlideModule {

    ...

    @Override
    public void registerComponents(Context context, Glide glide) {
        glide.register(GlideUrl.class, InputStream.class, new OkHttpGlideUrlLoader.Factory());
    }

}

发表评论

电子邮件地址不会被公开。 必填项已用*标注