框架【库】

Android图片加载库Glide

2019-04-24  本文已影响59人  Android高级工程师

前言

我觉得使用第三方的库时,要做到 知其然 知其所以然 欲然革之 弃之自然 好吧不装x了说人话就是,对一个库的了解程度可以化为为这样几个等级:

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

image.png

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相关代码隐去了,篇幅有限这一部分单独成篇详细探究。
先看这个方法主要完成了三件事:

# 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);

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

RequestManagerReriever类的注释

A collection of static methods for creating new RequestManagers or retrieving existing ones from activities and fragment.

这个类的职责就是创建新的RequestManager或者在activity和fragment中检索出已经存在的。
创建一个RequestManager的资料中很重要的一个就是LifeCycle

摘了比较核心的一段代码标记,加了注释。

  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对象创建RequestManager流程。

在这里插入图片描述

2.2 RequestManager、RequestBuilder

RequestManager见名知意,管理图片请求,启动、暂停、重新启动请求,依据所在组件的生命周期周期和网络做出恰当的动作

使用RequestManager对象一系列的load()方法最终能够得到一个RequestBuilder的对象,
RequestBuilder是一个泛型类,加载什么样的类型图片资源决定了他是什么类型,图片资源的来源可能是Recource、File、或者网络

RequestBuilder<T> requestBuidlder = requestManager.load(xxxx);

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

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

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这个优秀的开源库有了一个整体的认识,大体分为三个部分

点击+关注哦

上一篇 下一篇

猜你喜欢

热点阅读