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

# 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管理
  • 加载解析 我们会单独成篇吗,还可能会把缓存策略的应用纵向进行分析。最后再把我花了两个小时的整体架构图放上

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值