当前位置 : 主页 > 网络编程 > 其它编程 >

Android图片加载库Glide知其然知其所以然开篇

来源:互联网 收集:自由互联 发布时间:2023-07-02
前言我觉得使用第三方的库时要做到知其然知其所以然欲然革之弃之自然好吧不装x了说人话就是对一个库的了解程度可以化为为这样几个等级首先要做到 知其然 知其所以然 欲然革之
前言我觉得使用第三方的库时要做到知其然知其所以然欲然革之弃之自然好吧不装x了说人话就是对一个库的了解程度可以化为为这样几个等级首先要做到 知其然 知其所以然 欲然革之 弃之自然 好吧不装x了说人话就是对一个库的了解程度可以化为为这样几个等级

  • 首先要能够熟练使用它。
  • 然后理解其中的原理怎么实现的思考为什么这样实现
  • 再然后在了解原理的基础上如果想要实现库本身不支持的功能或者感觉实现的不好这样会情况下能够改造它。
  • 最后会用原理懂了能游刃有余的更改还觉得自己的才华得不到施展那就可以其之自然也就是自己造轮子。 接下来第一个阶段就先跳过了跳级进入第二个阶段。拆轮子探一探Glide这个库时怎么实现的。

整体Glide是怎样架构的大轮子如何转动起来通过这篇文章对Glide的整体有个认识然后逐一突破。 (这图画我了俩小时....,手动比心求赞)

1、关于Glide的创建

Glide的简单使用是下面这样的

Glide.with(context).load("http:xxxx").into(target)

先看看Glide.with()方法做了什么。Glide的withx方法的参数可以是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是单例如下。敲黑板这不就是传说中的双重效验锁。

NonNullpublic 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);的方法会在操作系统内存不足的时候会调用我们能想到这是清理缓存的好时机。

创建小结

# GlideBuildGlide 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) {//获取一个RequestManagerFragmentRequestManagerFragment current getRequestManagerFragment(fm, parentHint, isParentVisible);//试图在RequestManagerFragment中获取requestManagerRequestManager 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 requestBuidlder requestManager.load(xxxx);

得到RequestBuilder之后就可以对请求的图片资源做一些期望设置

  • 比如你希望他是多大的指定尺寸override()。
  • 希望它使用什么样子的裁剪规则centerCrop()centerInside();..
  • 期望他的缓存的机制是怎样的:diskCacheStrategy()。

RequestBuildler,都可以通过RequestOptions进行配置。ReuqestBuilder继承了BaseRequestOptions类BaseRequestOption这个类是连接RequestOption和RequestBuilder的桥梁通过这个类的对象对RequestOption进行一系列的设置。

Request有三个实现类RequestCoordinatorSingleRequest和ErrorRequestCoordinatorRequestCoodinator。

  • 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) 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 LoadStatus load(...) {...EngineJob engineJob engineJobFactory.build(...);DecodeJob decodeJob decodeJobFactory.build(...);...engineJob.addCallback(cb, callbackExecutor);//加载engineJob.start(decodeJob);//解码对二进制数据转换成图片根据配置进行编辑...return new LoadStatus(cb, engineJob);}

EngineJob.load实际加载图片数据的执行者加载完之后交给decodeJob处理。内部具体如何实现的单独成篇分析如这部分中线程池如何使用,Bitmap的使用技巧等。

以上对Glide这个优秀的开源库有了一个整体的认识大体分为三个部分

  • Glide创建
  • Request管理
  • 加载解析 我们会单独成篇吗还可能会把缓存策略的应用纵向进行分析。最后再把我花了两个小时的整体架构图放上

转:https://juejin.im/post/5cbea88cf265da03555c7f58

上一篇:MeiSheFaceStickerDesignPluginARSceneEditorInstruction
下一篇:没有了
网友评论