Glide全面理解
基本流程
with
- 判断context是否是Application
- 如果是的话,就不做判断,图片加载到程序崩溃才会取消
- 否则的话,会给当前Activity添加一个Fragment来监听其生命周期,来及时取消掉图片加载
- return 得到RequestManager对象(包含着对Glide的初始化)
ps:非主线程context会直接被当做是Application的context来使用
load
- fromUrl -> loadGeneric
Glide.buildStreamModelLoader(modelClass, context);
和Glide.buildFileDescriptorModelLoader(modelClass, context);
获取到ModelLoader
对象来加载图片- 将上面的东西作为参数获取到
DrawableTypeRequest
对象,主要提供asBitmap
和asGif
这两个方法,分别又创建了一个BitmapTypeRequest
和GifTypeRequest
,如果没有进行强制指定的话,那默认就是使用DrawableTypeRequest
- 真正的load方法是在
DrawableTypeRequest
的父类DrawableRequestBuilder
里面,这里面也是大多数我们常用的API了 - load方法还是返回
DrawableTypeRequest
,然后我们再来看into()
这个方法
into
into()方法也是整个Glide图片加载流程中逻辑最复杂的地方
- 来看GenericRequestBuilder类中的
into()
- 调用了
glide.buildImageViewTarget()
构建Target对像来最终显示图片 - 追溯到
buildTarget()
,如果调用了asBitmap()
就会去到BitmapImageViewTarget
对象,否则一般都是GlideDrawableImageViewTarget
对象,DrawableImageViewTarget
对象暂且不管 - 回到into(),看到
Request request = buildRequest(target);
和requestTracker.runRequest(request);
这两个核心方法,Request是用来发出加载图片请求的关键组件
requestTracker.runRequest(request)
-> GenericRequest.begin()
-> onSizeReady()
buildRequest()
调用obtainRequest
-> GenericRequest
的obtain
方法把全部参数组装起来,构建出request对象进行返回
requestTracker.runRequest(request);
requestTracker.runRequest()
: 调用GenericRequest.begin()
->- 占位图原理:当图片为null就最终去调用
setErrorPlaceholder
,而在开始的时候他就会调用target.onLoadStarted()
并传入占位图,这就是占位图的原理。 - 具体图片加载:当指定了图片大小则调用
onSizeReady()
, 否则调用target.getSize()
然后内部会根据ImageView计算宽高,最终还是会地调用onSizeReady()
- 占位图原理:当图片为null就最终去调用
onSizeReady
onSizeReady()
:- 对于
loadProvider.getModelLoader()
需要回到DrawableTypeRequest
的构造方法中,看到了调用了一个buildProvider()
方法,并把streamModelLoader
和fileDescriptorModelLoader
等参数传入到这个方法中,这两个ModelLoader
就是之前在loadGeneric()
方法中构建出来的。 buildProvidrer()
:- 调用了
glide.buildTranscoder()
: 构建出ResourceTranscoder
用于对图片转码,实际是构建出GifBitmapWrapperDrawableTranscoder
对象 - 调用
glide.buildDataProvider()
; 构建出DataLoadProvider
用于对图片编解码,实际构建出ImageVideoGifDrawableLoadProvider
对象 new ImageVideoModelLoader()
: 把之前loadGeneric()
的两个ModelLoader
封装到ImageVideoModelLoader
当中- 最后一步,
new FixedLoadProvider
把上面三个东西都封装进去,也就是onSizeReady
的loadProvider
对象了
- 调用了
- 所以
loadProvider.getModelLoader()
和loadProvider.getTranscoder()
得到的就是刚刚的ImageVideoModelLoader
和GifBitmapWrapperDrawableTranscoder
ImageVideoModelLoader.getResourceFetcher
: 调用streamLoader.getResourceFetcher()
方法获取一个DataFetcher,(streamLoader其实就是loadGeneric()中构建的StreamStringLoader),获取到HttpUrlFetcher
,并且new ImageVideoFetcher
对象并传入HttpUrlFetcher
,最后得到一个ImageVideoFetcher
作为返回- 将刚刚的诸多对象参数一同传入
engine.load()
- 对于
engine.load()
EngineJob engineJob = engineJobFactory.build();
: 获取EngineJob
用于开启线程,为异步加载图片做准备new DecodeJob
: 十分复杂后面详解EngineRunnable.run()
; 调用decode()
->decodeFromSource
->DecodeJob.decodeFromSource()
DecodeJob.decodeFromSource()
decodeSource()
获得一个Resource
对象,然后调用transformEncodeAndTranscode()
方法来处理这个Resource
对象。decodeSource()
: 调用onSizeReady()
得到的ImageVideoFetcher.loadData()
- 调用刚刚
HttpUrlFetcher.loadData()
: 这里就是网络通信层,获取到InputStream
并返回回去,并且封装到new ImageVideoWrapper()
当中返回 decodeFromSourceData(data);
: 这个data就是返回回来的ImageVideoWrapper
, 使用在onSizeReady得到的FixedLoadProvider.getSourceDecoder(GifBitmapWrapperResourceDecoder对象)
的decode
方法来对图片进行解码
- 调用刚刚
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)
又做了什么
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>
作为返回
EngineRunable.run
一层一层返回回到EngineRunable.decode()
方法中,接下来就是吧decode()
返回的Resource<GlideDrawable>
作为参数,调用onLoadComplete(resource);
,里面是调用Engine.load()
里面的EngineJob
的onResourceReady()
,这里面就是处理图片处理完成的回调
-
回调:就是在
Engine.load()
里面的addCallback
,往上追在onSizeReady里面engine.load()
传入this,也就是GenericRequest
本身自己实现了onResourceReady()
-
onResourceReady()
; 就是把资源提取出来然后调用target.onResourceReady(result, animation)
,这个target
就是在into()
作为参数glide.buildImageViewTarget()
返回的GlideDrawableImageViewTarget
对象(这个在很早之前分析过)
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还结合了一种弱引用的机制,共同完成了内存缓存功能
缓存对象准备
load()
->loadGeneric()
->Glide.buildStreamModelLoader()
->Glide.get(context).getLoaderFactory().buildModelLoader()
Glide.get()
->GlideBuilder.createGlide()
->memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
: 这里就是Glide使用的内存缓存,可以进去看一下也不难,实现了LruCahce算法
实际工作
- 缓存读取:
Engine.load()
方法当中的loadFromCache()
和loadFromActiveResources()
:从LruResourceCache
中获取到缓存图片之后会将它从缓存中移除,然后将这个缓存图片存储到activeResources
当中。activeResources
就是一个弱引用的HashMap,用来缓存正在使用中的图片,loadFromActiveResources()
方法就是从activeResources
这个HashMap当中取值的。使用activeResources
来缓存正在使用中的图片,可以保护这些图片不会被LruCache算法回收掉。 - 缓存写入:
EngineJob.handleResultOnMainThread()
: 通过EngineResourceFactory
构建出了资源对象EngineResource
,回调Engine
的onEngineJobComplete()
,然后就把资源放入到activeResources
里面了。 activeResources
是以弱引用缓存着正在使用的图片资源,LruCache
是缓存着没有在使用的图片资源。图片被使用就调用engineResource.acquire()
表示图片被使用数量+1,没有使用就调用engineResource.release()
表示图片使用数量-1。当图片引用数==0的时候,可以看到engineResource.release()
里面的listener.onResourceReleased()
,就是把资源从activeResources
中删除,然后添加到lruCache
中保存下来
硬盘缓存
Glide自己编写了
DiskLruCache
,但是原理是和Google那个差不多
硬盘缓存读取
Engine.load()
->EngineRunnable.run()
->EngineRunnable.decode()
->EngineRunnable.decodeFromeCache()
: 调用decodeJob.decodeResultFromCache()
和decodeJob.decodeSourceFromCache()
,这两个参数的区别就在设置的DiskCacheStrategy.RESULT
和DiskCacheStrategy.SOURCE
decodeJob.decodeResultFromCache()
: 直接loadFromCache()
然后transcode()
返回,之前分析过了decodeJob.decodeSourceFromCache()
: 因为是获取原始图片,所以key不需要这么多参数,所以调用了getOriginalKey
, 然后transformEncodeAndTranscode()
返回,之前也分析过了loadFromCache()
; 实际就是调用自己的DiskLruCache
获取缓存文件
硬盘缓存写入
- 原始图片缓存写入:
Engine.load()
->EngineRunnable.run()
->EngineRunnable.decode()
->EngineRunnable.decodeFromSource()
->EngineRunable.decodeSource()
->decodeJob.decodeFromSource()
->decodeJob.decodeSource()
->decodeJob.decodeFromSourceData()
->decodeJob.cacheAndDecodeSourceData()
: 然后就把原始图片写入到缓存了 - 转换图片缓存的写入:
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
接口有很多实现,主要关注ViewTarget
和 SimpleTarget
来实现重写就可以了
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
MultiTransformation
的transform()
就是遍历调用传进来的transhformation
的集合。
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()
查看内部,发现就是HttpUrlGlideUrlLoader
和HttpUrlFetcher
这两个类在工作,照着抄并且替换成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());
}
}