Android图片加载库Glide
前言
我觉得使用第三方的库时,要做到 知其然 知其所以然 欲然革之 弃之自然 好吧不装x了说人话就是,对一个库的了解程度可以化为为这样几个等级:
- 首先,要能够熟练使用它。
- 然后,理解其中的原理,怎么实现的,思考为什么这样实现
- 再然后,在了解原理的基础上,如果想要实现库本身不支持的功能或者感觉实现的不好,这样会情况下能够改造它。
- 最后,会用,原理懂了,能游刃有余的更改,还觉得自己的才华得不到施展,那就可以其之自然,也就是自己造轮子。
接下来,第一个阶段就先跳过了,跳级进入第二个阶段。拆轮子,探一探Glide这个库时怎么实现的。
整体Glide是怎样架构的,大轮子如何转动起来,通过这篇文章对Glide的整体有个认识然后逐一突破。
(这图画我了俩小时....,手动比心,求赞)

1、关于Glide的创建
Glide的简单使用是下面这样的
Glide.with(context).load("http:xxxx").into(target)
先看看Glide.with()方法做了什么。Glide的with(x)方法的参数可以是:Context、Activity、Fragment、View。 无论是哪种参数都会直接或者间接的调用下面这个方法:
private static RequestManagerRetriever getRetriever(@Nullable Context context){
Preconditions.checkNotNull(context,"..");
return Glide.get(context).getRequestManagerRetriever();
}
这个方法最终会返回一个RequestManagerRetriever对象。Glide.get(ctx)返回的是一个Glide对象,内部使用的单例模式,进程内Glide是单例,如下。敲黑板,这不就是传说中的双重效验锁。
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
return glide;
}
找到了Glide创建的地方,Glide.get(ctx)->checkAndInitializeGlide(ctx)->initializeGlide(ctx,glideBuilder),最终创建glide单例对象的重担落在了initializeGlide(..)方法上
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
Context applicationContext = context.getApplicationContext();
GeneratedAppGlideModule annotationGeneratedModulegetAnnotationGeneratedGlideModules();
....
Glide glide = builder.build(applicationContext);
...
applicationContext.registerComponentCallbacks(glide);
Glide.glide = glide;
}
我们源码中关于使用APT技术动态加载GeneratedAppGlideModule对象然后配置Glide相关代码隐去了,篇幅有限这一部分单独成篇详细探究。
先看这个方法主要完成了三件事:
- 使用APT技术动态加载GeneratedAppGlideModule对象然后配置Glide。(以后探其究竟)
- 使用构造者模式GlideBuilder创建了了Glide对象
- applicationContext.registerComponentCallbacks(glide),applicationContext注册了ComponentCallbacks监听,这里传入的上一步中新鲜创建的glide对象,glide实现了ComponentCallbacks2接口,接口中void onTrimMemory(@TrimMemoryLevel int level);的方法会在操作系统内存不足的时候会调用,我们能想到这是清理缓存的好时机。
创建小结
image.png
# GlideBuild
Glide build(@NonNull Context context) {
if (sourceExecutor == null) {...}
if (diskCacheExecutor == null) {...}
if (animationExecutor == null) {...}
...
if (memoryCache == null) {...}
if (diskCacheFactory == null) {...}
if (engine == null) {...}
return new Glide(context, engine,memoryCache,bitmapPool,arrayPool...)
}
如上图经过层层最终调用initializeGlide(),这个方法中使用GlideBuilder对象够建出Glide对象,值得关注的是他是一个单例。而且当在GlideBuider没有设置响应参数的时候会生成默认的参数供GlideBuilder创建出Glide对象。
2、关于请求管理
2.1、RequestManagerRetriever
书接上回,我们已经对Glide这个类的创建有了一个大体的认知。
还是那行代码,
RequestManager requestManager = Glide.with(this);
这行代码顺序的做了三件事
- 1、通过Glide glide = Glide.get(context)最终创建得到了一个Glide单例对象;
- 2、调用glide.getRetriever()得到requestManagerRetriever对象
- 3、RequestManager manager = requestManagerRetriever.getRequestManager(context)得到一个RequestManager的对象。
RequestManagerReriever类的注释
A collection of static methods for creating new RequestManagers or retrieving existing ones from activities and fragment.
这个类的职责就是创建新的RequestManager或者在activity和fragment中检索出已经存在的。
创建一个RequestManager的资料中很重要的一个就是LifeCycle
- 有两个类实现了LifeCycle分别是ActivityFragmentLifecycle和ApplicationLifecycle。主要区别就在于,ActivityFragmentLifecycle有感知Fragment/Activity声明周期的能力。
- 如果传入的是Fragment或者Acitivy,requestManagerReriever视图创建一个RequestManagerFragment对象,与其绑定,这样就实现了对Activity,或者Fragment声明周期的感知。
- 如果传入的是ApplicationContext就会传入有两个类实现了LifeCycle分别是ActivityFragmentLifecycle和ApplicationLifecycle。
摘了比较核心的一段代码标记,加了注释。
private RequestManager fragmentGet(@NonNull Context context,FragmentManager fm,Fragment parentHint,boolean isParentVisible) {
//获取一个RequestManagerFragment
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
//试图在RequestManagerFragment中获取requestManager
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
//如果为空就创建一个并且存到RequestManagerFragment中
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
注意的点
- RequestManagerReriever什么时候创建的呢?在GlideBuilder中build方法中new了一个通过Glide的构造方法传入的。
- 当RequestManagerReriever.get(view)的时候,会查找view所在的Activity进而去创创建Requestmanager,如果没有找到所在Activity就使用ApplicationLifecycle构建Requestmanager。
总结下RequestManagerReriever对象创建RequestManager流程。
2.2 RequestManager、RequestBuilder
RequestManager见名知意,管理图片请求,启动、暂停、重新启动请求,依据所在组件的生命周期周期和网络做出恰当的动作
使用RequestManager对象一系列的load()方法最终能够得到一个RequestBuilder的对象,
RequestBuilder是一个泛型类,加载什么样的类型图片资源决定了他是什么类型,图片资源的来源可能是Recource、File、或者网络
RequestBuilder<T> requestBuidlder = requestManager.load(xxxx);
得到RequestBuilder之后,就可以对请求的图片资源做一些期望设置
- 比如你希望他是多大的,指定尺寸:override()。
- 希望它使用什么样子的裁剪规则:centerCrop(),centerInside();..
- 期望他的缓存的机制是怎样的:diskCacheStrategy()。
RequestBuildler,都可以通过RequestOptions进行配置。ReuqestBuilder继承了BaseRequestOptions类,BaseRequestOption这个类是连接RequestOption和RequestBuilder的桥梁,通过这个类的对象对RequestOption进行一系列的设置。
Request有三个实现类,RequestCoordinator,SingleRequest和ErrorRequestCoordinator,RequestCoodinator。
- RequestCoordinator中包含两个Request,一个是 primary, error。RequestCoordinator使用primary发起请求,如果primary请求失败了,就调用error请求。
- SingleReuqest 实现了Request方法,加载来自不同类型的图片资源。
- ThumbnailRequestCoordinator 同时加载缩略图和原始图。
RequestBuilder 构建ErrorRequestCoordinator对象的方法为例。
private Request buildRequestRecursive(..) {
//构建请求控制
ErrorRequestCoordinator errorRequestCoordinator = null;
if (errorBuilder != null) {
errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
//构建的主请求
Request mainRequest =(...);
if (errorRequestCoordinator == null) {
return mainRequest;
}
int errorOverrideWidth = errorBuilder.getOverrideWidth();
int errorOverrideHeight = errorBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !errorBuilder.isValidOverride()) {
errorOverrideWidth = requestOptions.getOverrideWidth();
errorOverrideHeight = requestOptions.getOverrideHeight();
}
//构建错误请求
Request errorRequest =
errorBuilder.buildRequestRecursive(..);
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
整个Request构建管理的构成如下
这只是一个整体的流程,关于更详细的Request管理,包括如果感知声明周期的,重复请求如何管理,参数设置的原理等等单独成篇分析。
3、Engine
Request对象的begin()方法根据图片不同的来源去加载,获取到期望尺寸之后就会调用onSizeReady(),传入一系列参数信息。
onSizeReady(){
...
loadStatus =
engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this,
callbackExecutor);
...
}
engin.load()
public synchronized <R> LoadStatus load(...) {
...
EngineJob<R> engineJob =engineJobFactory.build(...);
DecodeJob<R> decodeJob =decodeJobFactory.build(...);
...
engineJob.addCallback(cb, callbackExecutor);//加载
engineJob.start(decodeJob);//解码,对二进制数据转换成图片根据配置进行编辑
...
return new LoadStatus(cb, engineJob);
}
EngineJob.load实际加载图片数据的执行者,加载完之后交给decodeJob处理。内部具体如何实现的单独成篇分析,如这部分中线程池如何使用,Bitmap的使用技巧等。
结
以上对Glide这个优秀的开源库有了一个整体的认识,大体分为三个部分
- Glide创建
- Request管理
- 加载解析 我们会单独成篇吗,还可能会把缓存策略的应用纵向进行分析。最后再把我花了两个小时的整体架构图放上
-
在这里插入图片描述