Android图片加载库Glide 知其然知其因此然 开篇

前言

我以为使用第三方的库时,要作到 知其然 知其因此然 欲然革之 弃之天然 好吧不装x了说人话就是,对一个库的了解程度能够化为为这样几个等级:缓存

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

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

一、关于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是单例,以下。敲黑板,这不就是传说中的双重效验锁。app

@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(..)方法上ide

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相关代码隐去了,篇幅有限这一部分单独成篇详细探究。ui

先看这个方法主要完成了三件事:this

  • 使用APT技术动态加载GeneratedAppGlideModule对象而后配置Glide。(之后探其究竟)
  • 使用构造者模式GlideBuilder建立了了Glide对象
  • applicationContext.registerComponentCallbacks(glide),applicationContext注册了ComponentCallbacks监听,这里传入的上一步中新鲜建立的glide对象,glide实现了ComponentCallbacks2接口,接口中void onTrimMemory(@TrimMemoryLevel int level);的方法会在操做系统内存不足的时候会调用,咱们能想到这是清理缓存的好时机。

建立小结

image

# 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对象。spa

二、关于请求管理

2.一、RequestManagerRetriever

书接上回,咱们已经对Glide这个类的建立有了一个大致的认知。操作系统

仍是那行代码,

RequestManager requestManager = Glide.with(this);
复制代码

这行代码顺序的作了三件事

  • 一、经过Glide glide = Glide.get(context)最终建立获得了一个Glide单例对象;
  • 二、调用glide.getRetriever()获得requestManagerRetriever对象
  • 三、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流程。

image

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管理,包括若是感知声明周期的,重复请求如何管理,参数设置的原理等等单独成篇分析。

三、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管理
  • 加载解析 咱们会单独成篇吗,还可能会把缓存策略的应用纵向进行分析。最后再把我花了两个小时的总体架构图放上
    image
相关文章
相关标签/搜索