Glide V4 源码浅析(上)-- 主流程分析

1. Glide的作用

图片加载基本是每个APP都需要的基础功能,而在使用的过程中我们需要考虑到图片的加载方式、缓存、多媒体等问题,而Glide帮我们完成这一类的工作,并且提供了一套易用的API。

Glide的官方介绍如下:

Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。

总结起来它的优势如下:

  1. 可加载多媒体格式多样化,如Gif、Webp、Video等
  2. 加载过程绑定生命周期,通过生命周期管理实现更好的实现资源利用
  3. 高效缓存策略,拥有2层内存缓存和磁盘缓存。

2. Glide的使用方法

由于Glide的API十分灵活,开发者可以通过各种设置来达到不同加载效果,因此这里仅就最基础的使用方式进行分析,至于glide下载与安装可以直接参考官方项目地址下载安装最新版。

Glide项目地址:github

加载一张圆形图片

//初始化一个RequestOptions,并在其中通过circleCropTransform()设置圆形
RequestOptions mRequestOptions = new RequestOptions().circleCropTransform();
//通过Glide将图片地址为myUrl的图片以圆形的裁剪方式加载到imageView中
Glide.with(fragment)
    .load(myUrl)
    .apply(mRequestOptions)
    .into(imageView);

3. Glide的工作原理

根据上面的例子,Glide主要的流程如下图


Glide主要流程

短短几行代码就实现了将图片加载到我们指定地方,其中Glide框架帮我们完成了资源的不同类型(PNG、JPG、WEBP、GIF)和不同来源(网络、本地)的加载,以及对应的缓存策略。

3.1 Glide.with()

Glide.with()一共有个6重载方法,其中一个已经被标记为Deprecated了,分别对应在不同的情景下使用,每种重载方法的调用逻辑是一致的,都是先调用getRetriever(),之后再调用get()方法获取RequestManager,这里我们以比较常用的Activity作为例子

  public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
  }
3.1.1 如上文写的一样先调用getRetriever获取RequestManagerRetriever
  private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    //对传入的Context进行判空
    Preconditions.checkNotNull(
        context,
        "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
            + "returns null (which usually occurs when getActivity() is called before the Fragment "
            + "is attached or after the Fragment is destroyed).");
    return Glide.get(context).getRequestManagerRetriever();
  }

其中在Glide.get(context)中,完成了对Glide单例的初始化

  //双重验证单例
  public static Glide get(@NonNull Context context) {
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context);
        }
      }
    }

    return glide;
  }

初始化Glide会在gilde.build()时创建RequestManagerRetriever

  @NonNull
  Glide build(@NonNull Context context) {
    //创建默认参数
    ......

    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);

    //创建将参数传入Glide的构造函数完成初始化
    ......
  }

RequestManagerRetriever根据官方注解的描述是一个用于创建或者获取现有的RequestManager的集合,此时我们在with()方法中通过getRetriever(activity)获取到生成的requestManagerRetriever.

3.1.2 再通过RequestManagerRetriever获取RequestManager.

RequestManagerRetriever的get()方法和with()方法一样拥有许多重载方法,我们还是继续以Activity为例

  public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
      //如果当前不在主线程,通过调用get(@NonNull Context context)调用getApplicationManager
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      return fragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }
  
  
  private RequestManager fragmentGet(@NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

可见在调用Activity的get时实际是通过fragmentGet方法中的factory.build()产生返回的requestManager的。

 //RequestManagerRetriever的构造函数中创建了factory
 public RequestManagerRetriever(@Nullable RequestManagerFactory factory) {
    //若创建RequestManagerRetriever未传入RequestManagerFactory,则使用DEFAULT_FACTORY作为factory
    this.factory = factory != null ? factory : DEFAULT_FACTORY;
    handler = new Handler(Looper.getMainLooper(), this /* Callback */);
  }
  
 private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() {
    @NonNull
    @Override
    public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle,
        @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) {
      //创建对应的RequestManager
      return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
    }
  };

在factory中通过new RequestManager()创建所需的RequestManager。至此Glide.with()分析完成

3.2 load()

在load方法中我们一般传入我们所需的资源文件,Glide提供了很多种重载方法用于兼容不同类型的加载方式,如Bitmap,Drawable,Uri等。
在RequestManager中对于load方法一般直接通过asDrawable().load(xxx)方法继续调用。当然除了asDrawable(),Glide还提供asFile()、asGif()、asBitmap()等方法。而他们最终都会调用到as(xxx)方法用于返回一个RequestBuilder

  public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
  }
  
  public <ResourceType> RequestBuilder<ResourceType> as(
      @NonNull Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
  }

因此上文中asDrawable().load(xxx)方法最终会调用到RequestBuilder中的load(xxx)方法,而这些方法无一例外会调用到loadGeneric()方法

  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }

在loadGeneric仅对model进行了赋值,因此整个load()操作总结下主要作用如下:1.生成RequestBuilder,2.对传入model进行赋值保存。

3.3 apply()

我们使用 apply() 方法将我们自定义的requestOptions传入

  public RequestBuilder<TranscodeType> apply(@NonNull RequestOptions requestOptions) {
    Preconditions.checkNotNull(requestOptions);
    this.requestOptions = getMutableOptions().apply(requestOptions);
    return this;
  }
  
  //获取现有的RequestOptions
  protected RequestOptions getMutableOptions() {
    //如果目前的requestOptions与defaultRequestOptions一致则表明未进行修改,为了保证源文件不被修改,使用clone方法创建一个新的requestOptions回传回去
    return defaultRequestOptions == this.requestOptions
        ? this.requestOptions.clone() : this.requestOptions;
  }

由此可知最终会调用到RequestBuilder中RequestOptions的apply()方法

  public RequestOptions apply(@NonNull RequestOptions other) {
    if (isAutoCloneEnabled) {
      return clone().apply(other);
    }

    if (isSet(other.fields, SIZE_MULTIPLIER)) {
      sizeMultiplier = other.sizeMultiplier;
    }
    if (isSet(other.fields, USE_UNLIMITED_SOURCE_GENERATORS_POOL)) {
      useUnlimitedSourceGeneratorsPool = other.useUnlimitedSourceGeneratorsPool;
    }
    if (isSet(other.fields, USE_ANIMATION_POOL)) {
      useAnimationPool = other.useAnimationPool;
    }
    if (isSet(other.fields, DISK_CACHE_STRATEGY)) {
      diskCacheStrategy = other.diskCacheStrategy;
    }
    if (isSet(other.fields, PRIORITY)) {
      priority = other.priority;
    }
    if (isSet(other.fields, ERROR_PLACEHOLDER)) {
      errorPlaceholder = other.errorPlaceholder;
    }
    if (isSet(other.fields, ERROR_ID)) {
      errorId = other.errorId;
    }
    if (isSet(other.fields, PLACEHOLDER)) {
      placeholderDrawable = other.placeholderDrawable;
    }
    if (isSet(other.fields, PLACEHOLDER_ID)) {
      placeholderId = other.placeholderId;
    }
    if (isSet(other.fields, IS_CACHEABLE)) {
      isCacheable = other.isCacheable;
    }
    if (isSet(other.fields, OVERRIDE)) {
      overrideWidth = other.overrideWidth;
      overrideHeight = other.overrideHeight;
    }
    if (isSet(other.fields, SIGNATURE)) {
      signature = other.signature;
    }
    if (isSet(other.fields, RESOURCE_CLASS)) {
      resourceClass = other.resourceClass;
    }
    if (isSet(other.fields, FALLBACK)) {
      fallbackDrawable = other.fallbackDrawable;
    }
    if (isSet(other.fields, FALLBACK_ID)) {
      fallbackId = other.fallbackId;
    }
    if (isSet(other.fields, THEME)) {
      theme = other.theme;
    }
    if (isSet(other.fields, TRANSFORMATION_ALLOWED)) {
      isTransformationAllowed = other.isTransformationAllowed;
    }
    if (isSet(other.fields, TRANSFORMATION_REQUIRED)) {
      isTransformationRequired = other.isTransformationRequired;
    }
    if (isSet(other.fields, TRANSFORMATION)) {
      transformations.putAll(other.transformations);
      isScaleOnlyOrNoTransform = other.isScaleOnlyOrNoTransform;
    }
    if (isSet(other.fields, ONLY_RETRIEVE_FROM_CACHE)) {
      onlyRetrieveFromCache = other.onlyRetrieveFromCache;
    }

    // Applying options with dontTransform() is expected to clear our transformations.
    if (!isTransformationAllowed) {
      transformations.clear();
      fields &= ~TRANSFORMATION;
      isTransformationRequired = false;
      fields &= ~TRANSFORMATION_REQUIRED;
      isScaleOnlyOrNoTransform = true;
    }

    fields |= other.fields;
    options.putAll(other.options);

    return selfOrThrowIfLocked();
  }

在apply()方法中通过isSet方法比较对应的标志位的值从而对相应属性进行修改。此时apply()逻辑完成,主要用于对用户的设置进行配置。

3.4 into()

into()方法是我们此次分析流程中的最后一步,可以看到前文提到的with()、load()、apply()这些方法中均未涉及到图片的加载和显示过程,更多是做一些初始化和参数的配置。因此可以猜测缓存加载的相关操作应该是房子into()中

  public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    //省略部分代码,根据imageView的ScaleType设置相应的RequestOptions
    ......

    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions);
  }
  
  
  private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @NonNull RequestOptions options) {
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    options = options.autoClone();
    //初始化Request
    Request request = buildRequest(target, targetListener, options);

    Request previous = target.getRequest();
    //将此次Request与之前的Request相比较看能否复用
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      request.recycle();
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        previous.begin();
      }
      return target;
    }

    requestManager.clear(target);
    //将当前生成的request赋值给target
    target.setRequest(request);
    //通过requestManager追踪target和request
    requestManager.track(target, request);

    return target;
  }
3.4.1 生成对应的ViewTarget

根据传入的view和上文提到资源类型(asDrawable()所传入的类型)生成一个对应的ViewTarget,通过glideContext.buildImageViewTarget的层层调用最终会调用到ImageViewTargetFactory中的buildTarget方法中

  public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
      @NonNull Class<Z> clazz) {
    if (Bitmap.class.equals(clazz)) {
      return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
      return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
    } else {
      throw new IllegalArgumentException(
          "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
  }

这里会传入资源类型生成对应的ViewTarget

3.4.2 生成对应的request

通过buildRequest最终会调用buildRequestRecursive()方法

private Request buildRequestRecursive(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      RequestOptions requestOptions) {

    // 根据使用glide加载图片时是否传入了errorBuilder(通过error()方法传入)来确定是否会生成errorRequestCoordinator
    ErrorRequestCoordinator errorRequestCoordinator = null;
    if (errorBuilder != null) {
      errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }

    //初始化mainRequest
    Request mainRequest =
        buildThumbnailRequestRecursive(
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions);

    //如果未生成errorRequestCoordinator则直接返回mainRequest
    if (errorRequestCoordinator == null) {
      return mainRequest;
    }

    int errorOverrideWidth = errorBuilder.requestOptions.getOverrideWidth();
    int errorOverrideHeight = errorBuilder.requestOptions.getOverrideHeight();
    if (Util.isValidDimensions(overrideWidth, overrideHeight)
        && !errorBuilder.requestOptions.isValidOverride()) {
      errorOverrideWidth = requestOptions.getOverrideWidth();
      errorOverrideHeight = requestOptions.getOverrideHeight();
    }

    //如果errorRequestCoordinator存在则生成errorRequest并返回
    Request errorRequest = errorBuilder.buildRequestRecursive(
        target,
        targetListener,
        errorRequestCoordinator,
        errorBuilder.transitionOptions,
        errorBuilder.requestOptions.getPriority(),
        errorOverrideWidth,
        errorOverrideHeight,
        errorBuilder.requestOptions);
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }

这里我们可以看到生成request时会先通过errorBuilder存在与否分别返回不同的request,但无论返回哪个request,其中都需要mainRequest。

private Request buildThumbnailRequestRecursive(
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      RequestOptions requestOptions) {
    //判断是否存在thumbnailBuilder,由此决定是否创建thumbRequest
    if (thumbnailBuilder != null) {
      //省略部分代码
      ......
      //创建thumbRequest
      Request thumbnailRequest =
          obtainRequest(
              target,
              targetListener,
              thumbnailOptions,
              coordinator,
              transitionOptions,
              getThumbnailPriority(priority),
              overrideWidth,
              overrideHeight);
      //将fullRequest和thumbnailRequest放入coordinator中
      coordinator.setRequests(fullRequest, thumbnailRequest);
      return coordinator;
    //若未传入对应的thumbnailBuilder判断是否传入对应的thumbSizeMultiplier(float类型的缩放比例),与上方逻辑类似创建对应的thumbnailRequest并和fullRequest放入coordinator中,并返回。
    } else if (thumbSizeMultiplier != null) {
      //省略部分代码
    } else {
      // 若无thumbnail相关参数,则直接调用obtainRequest返回
      return obtainRequest(
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight);
    }
  }

可见buildThumbnailRequestRecursive()逻辑与buildRequestRecursive逻辑类似,用于根据thumbnail生成对应的coordinator,但是对应的request的生成均是由obtainRequest()方法实现

private Request obtainRequest(
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      RequestOptions requestOptions,
      RequestCoordinator requestCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight) {
    //调用了SingleRequest的obtain
    return SingleRequest.obtain(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListener,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory());
  }
  
  
  //该方法最终会调用到SingleRequest的init()方法,该方法也仅仅是用于初始化赋值,并将request的状态改为PENDING
  private void init(
      Context context,
      GlideContext glideContext,
      Object model,
      Class<R> transcodeClass,
      RequestOptions requestOptions,
      int overrideWidth,
      int overrideHeight,
      Priority priority,
      Target<R> target,
      RequestListener<R> targetListener,
      RequestListener<R> requestListener,
      RequestCoordinator requestCoordinator,
      Engine engine,
      TransitionFactory<? super R> animationFactory) {
    this.context = context;
    this.glideContext = glideContext;
    this.model = model;
    this.transcodeClass = transcodeClass;
    this.requestOptions = requestOptions;
    this.overrideWidth = overrideWidth;
    this.overrideHeight = overrideHeight;
    this.priority = priority;
    this.target = target;
    this.targetListener = targetListener;
    this.requestListener = requestListener;
    this.requestCoordinator = requestCoordinator;
    this.engine = engine;
    this.animationFactory = animationFactory;
    status = Status.PENDING;
  }

经过多层嵌套,request的生成终于完成了,虽然代码量不少,但是整体逻辑还是比较清晰的,先根据是否有errorBuilder确定最外层的errorRequestCoordinator是否存在,再在buildThumbnailRequestRecursive()中是否有thumbnail相关参数来确定内部的coordinator是否存在。
如果两者均存在,则生成的request为ErrorRequestCoordinator(ThumbnailRequestCoordinator(fullRequest,thumbRequest),errorRequest)。

3.4.3 通过requestManager追踪target和request
  void track(@NonNull Target<?> target, @NonNull Request request) {
    //分别用targetTracker 追踪 target,requestTracker 调用request
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }

targetTracker在官方注释中表示这个类的作用是用于对target进行相应生命周期的管理,而它的track方法也十分简单,仅仅是将target加入到它的一个内部集合类targets中

  public void track(@NonNull Target<?> target) {
    targets.add(target);
  }

而requestTrack与targetTracker类似,也是将传入的request保存到内部集合类中,用于对其进行相应生命周期管理,而且该方法还会调用request的begin方法

  public void runRequest(@NonNull Request request) {
    requests.add(request);
    //当前非paused状态时,调用request的begin,否则加入pendingRequests队列中
    if (!isPaused) {
      request.begin();
    } else {
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }

在上文关于request的创建中我们知道了,这里的request指的是singleRequest,因此会调用它的begin方法

  @Override
  public void begin() {
    //省略部分异常判断的代码
    ......

    //判断当前status是否是已完成(即完成相应资源的加载)。
    if (status == Status.COMPLETE) {
      onResourceReady(resource, DataSource.MEMORY_CACHE);
      return;
    }
    
    //将状态更变为WAITING_FOR_SIZE
    status = Status.WAITING_FOR_SIZE;
    //判断用户是否通过requestOptions指定合法的宽高
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      //如果指定了合法的宽高则直接调用onSizeReady()
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      //如果未指定,则由上文生成的viewTarget获取对应的size
      target.getSize(this);
    }

    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
      target.onLoadStarted(getPlaceholderDrawable());
    }
    if (IS_VERBOSE_LOGGABLE) {
      logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    }
  }

target.getSize(this)方法,将singleRequest本身作为一个callback传递了进去,当target获取到了所需尺寸后则会通过传入的callback调用onSizeReady()方法,所以之后的流程还是会进入到onSizeReady()方法

  @Override
  public void onSizeReady(int width, int height) {
    //省略部分异常判断代码
    ......
    
    //将目前的状态变更为RUNNING
    status = Status.RUNNING;

    float sizeMultiplier = requestOptions.getSizeMultiplier();
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

    if (IS_VERBOSE_LOGGABLE) {
      logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
    }
    
    //通过engine.load()进行加载,并返回loadStatus
    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);

    // This is a hack that's only useful for testing right now where loads complete synchronously
    // even though under any executor running on any thread but the main thread, the load would
    // have completed asynchronously.
    if (status != Status.RUNNING) {
      loadStatus = null;
    }
    if (IS_VERBOSE_LOGGABLE) {
      logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
  }

engine是在Glide在初始化build时创建的,官方注释描述该类用于启动加载和管理对应的活动资源和缓存资源。

    public <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      boolean isScaleOnlyOrNoTransform,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean useAnimationPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb) {
    Util.assertMainThread();
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

    //创建本次加载的资源对应的key
    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);
    
    //从活动资源查找对应资源是否存在
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }
    
    //如未找到,从缓存资源中查找对应资源是否存在
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }
    
    //如果内存缓存未找到则查找目前正在运行的加载任务中是否存在相同的任务
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
      current.addCallback(cb);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }

    //全部未命中后创建engineJob和decodeJob
    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);

    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);

    //将创建的engineJob与key绑定存入jobs中,让后续任务可以查找
    jobs.put(key, engineJob);

    //将cb(即上文中的SingleRequest)加入callback,继续向下传递
    engineJob.addCallback(cb);
    //由engineJob启动decodeJob
    engineJob.start(decodeJob);

    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
  }

在此方法中涉及到了两级的内存缓存的查找,后续再详细讨论。我们继续关注加载的主流程,在内存缓存未命中的时候我们创建分别创建了EngineJob和DecodeJob。根据官方注释,EngineJob是用来管理添加和删除加载时callback的类,并会在完成时通知对应callback。而DecodeJob正如它的名字是一个解码任务负责从缓存数据或者原始数据解码的类。engineJob.start(decodeJob)则会开启decodeJob的运行

  public void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }

在线程池中运行decodeJob。

  @Override
  public void run() {
    GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
    DataFetcher<?> localFetcher = currentFetcher;
    try {
      //判断该任务是否取消
      if (isCancelled) {
        notifyFailed();
        return;
      }
      //运行任务
      runWrapped();
    } catch (Throwable t) {
      //异常情况处理
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "DecodeJob threw unexpectedly"
            + ", isCancelled: " + isCancelled
            + ", stage: " + stage, t);
      }
      if (stage != Stage.ENCODE) {
        throwables.add(t);
        notifyFailed();
      }
      if (!isCancelled) {
        throw t;
      }
    } finally {
      if (localFetcher != null) {
        localFetcher.cleanup();
      }
      GlideTrace.endSection();
    }
  }
  
  private void runWrapped() {
    //根据runReason状态调用不同处理逻辑,runReason在DecodeJob初始化时会被赋值为INITIALIZE
    switch (runReason) {
      case INITIALIZE:
        //获取下个stage和generator
        stage = getNextStage(Stage.INITIALIZE);
        currentGenerator = getNextGenerator();
        //状态更新后调用的runGenerators
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }

这里stage更新会根据当前的缓存状态来改变,如果缓存未命中且未限制仅能从缓存中读取,则状态会变为SOURCE。getNextGenerator()方法则会根据当前的stage状态生成不同的currentGenerator。

  private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    //判断任务是否被取消,违背取消则去调用currentGenerator的startNext()方法用于查找对应缓存,而while循环会不断的更新stage和currentGenerator的状态。
    while (!isCancelled && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

      //如果stage为SOURCE,则会调用reschedule
      if (stage == Stage.SOURCE) {
        //reschedule会将runReason变为SWITCH_TO_SOURCE_SERVICE,并通过callback的reschedule方法重新调用runWrapped从而达到状态更新目的
        reschedule();
        return;
      }
    }
    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
      notifyFailed();
    }
  }

关于文件缓存暂时略过,后续再详细讨论。因此我们目前以SourceGenerator为例,进行接下来流程的讨论

  @Override
  public boolean startNext() {
    //判断dataToCache状态来确定是否需要生成对应的sourceCacheGenerator。
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }

    //如果生成了对应的sourceCacheGenerator,则调用其startNext方法,并返回true
    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
      return true;
    }
    sourceCacheGenerator = null;

    loadData = null;
    boolean started = false;
    //循环查找ModelLoader中是否存在加载对应数据的ModelLoader
    while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        //找到能处理的loadData后,调用loadData方法进行加载
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

loadData加载对应资源成功后,会通过传入的第二个参数this回调onDataReady方法。

  @Override
  public void onDataReady(Object data) {
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
    //判断数据是否可以缓存
    if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      //若允许缓存,则进行赋值,且调用cb的reschedule()方法
      dataToCache = data;
      cb.reschedule();
    } else {
      //否则直接调用cb的onDataFetcherReady()方法
      cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
          loadData.fetcher.getDataSource(), originalKey);
    }
  }

如上文所述reschedule方法会重新调用DecodeJob的runWrapped()方法,最终会回到startNext()方法中,但此时dataToCache已被赋值,因此会调用cacheData()方法

  private void cacheData(Object dataToCache) {
    long startTime = LogTime.getLogTime();
    try {
      Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
      DataCacheWriter<Object> writer =
          new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
      originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
      helper.getDiskCache().put(originalKey, writer);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Finished encoding source to cache"
            + ", key: " + originalKey
            + ", data: " + dataToCache
            + ", encoder: " + encoder
            + ", duration: " + LogTime.getElapsedMillis(startTime));
      }
    } finally {
      loadData.fetcher.cleanup();
    }

    sourceCacheGenerator =
        new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
  }

该方法主要用于对source数据进行缓存,以及生成对应的sourceCacheGenerator。之后通过sourceCacheGenerator来通加载缓存数据,加载完成后最终还是会调用cb.onDataFetcherReady()方法,也就是DecodeJob的onDataFetcherReady()方法。

  @Override
  public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
      DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;
    this.currentData = data;
    this.currentFetcher = fetcher;
    this.currentDataSource = dataSource;
    this.currentAttemptingKey = attemptedKey;
    //判断当前线程是否一致,不一致则修改runReason为DECODE_DATA,再通过reschedule方法重新调用run()
    if (Thread.currentThread() != currentThread) {
      runReason = RunReason.DECODE_DATA;
      callback.reschedule(this);
    } else {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        decodeFromRetrievedData();
      } finally {
        GlideTrace.endSection();
      }
    }
  }

在onDataFetcherReady方法中会在赋值操作后通过decodeFromRetrievedData()方法对数据进行解析。decodeFromRetrievedData()方法最终通过层层调用会获取到对应的LoadPath对象并调用其load()方法进行解析。并在最后通过notifyEncodeAndRelease()方法进行回调通知。

  public Resource<Transcode> load(DataRewinder<Data> rewinder, @NonNull Options options, int width,
      int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException {
    List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire());
    try {
      return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
    } finally {
      listPool.release(throwables);
    }
  }
  
  private Resource<Transcode> loadWithExceptionList(DataRewinder<Data> rewinder,
      @NonNull Options options,
      int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback,
      List<Throwable> exceptions) throws GlideException {
    Resource<Transcode> result = null;
    //循环调用decodePaths中的DecodePath的decode进行解析
    for (int i = 0, size = decodePaths.size(); i < size; i++) {
      DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i);
      try {
        result = path.decode(rewinder, width, height, options, decodeCallback);
      } catch (GlideException e) {
        exceptions.add(e);
      }
      if (result != null) {
        break;
      }
    }

    if (result == null) {
      throw new GlideException(failureMessage, new ArrayList<>(exceptions));
    }

    return result;
  }

可见LoadPath的load()方法最终会调用到loadWithExceptionList()方法,并在此方法中循环调用decodePaths中DecodePath的decode进行解析,获取result。

  public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
      @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
    Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
    Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
    return transcoder.transcode(transformed, options);
  }

  @NonNull
  private Resource<ResourceType> decodeResource(DataRewinder<DataType> rewinder, int width,
      int height, @NonNull Options options) throws GlideException {
    List<Throwable> exceptions = Preconditions.checkNotNull(listPool.acquire());
    try {
      return decodeResourceWithList(rewinder, width, height, options, exceptions);
    } finally {
      listPool.release(exceptions);
    }
  }

DecodePath的decode方法首先与LoadPath的load()方法类似,通过decodeResourceWithList循环调用ResourceDecoder进行解析。之后通过callback.onResourceDecoded()回调方法将对应的结果传入。

  @Synthetic
  @NonNull
  <Z> Resource<Z> onResourceDecoded(DataSource dataSource,
      @NonNull Resource<Z> decoded) {
    @SuppressWarnings("unchecked")
    Class<Z> resourceSubClass = (Class<Z>) decoded.get().getClass();
    Transformation<Z> appliedTransformation = null;
    Resource<Z> transformed = decoded;
    if (dataSource != DataSource.RESOURCE_DISK_CACHE) {
      appliedTransformation = decodeHelper.getTransformation(resourceSubClass);
      transformed = appliedTransformation.transform(glideContext, decoded, width, height);
    }
    if (!decoded.equals(transformed)) {
      decoded.recycle();
    }

    final EncodeStrategy encodeStrategy;
    final ResourceEncoder<Z> encoder;
    if (decodeHelper.isResourceEncoderAvailable(transformed)) {
      encoder = decodeHelper.getResultEncoder(transformed);
      encodeStrategy = encoder.getEncodeStrategy(options);
    } else {
      encoder = null;
      encodeStrategy = EncodeStrategy.NONE;
    }

    Resource<Z> result = transformed;
    //省略部分代码
    ....
    return result;
  }
  
  
  @SuppressWarnings("unchecked")
  <Z> Transformation<Z> getTransformation(Class<Z> resourceClass) {
    Transformation<Z> result = (Transformation<Z>) transformations.get(resourceClass);
    if (result == null) {
      for (Entry<Class<?>, Transformation<?>> entry : transformations.entrySet()) {
        if (entry.getKey().isAssignableFrom(resourceClass)) {
          result = (Transformation<Z>) entry.getValue();
          break;
        }
      }
    }

    if (result == null) {
      if (transformations.isEmpty() && isTransformationRequired) {
        throw new IllegalArgumentException(
            "Missing transformation for " + resourceClass + ". If you wish to"
                + " ignore unknown resource types, use the optional transformation methods.");
      } else {
        return UnitTransformation.get();
      }
    }
    return result;
  }

在Engine.load()的时候会将Glide初始化时创建的transformations进行遍历,寻找key对应的Transformation。之后将结果返回到onDataFetcherReady方法中,继续调用notifyEncodeAndRelease()方法,进行回调通知。

  private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
    if (resource instanceof Initializable) {
      ((Initializable) resource).initialize();
    }

    Resource<R> result = resource;
    LockedResource<R> lockedResource = null;
    if (deferredEncodeManager.hasResourceToEncode()) {
      lockedResource = LockedResource.obtain(resource);
      result = lockedResource;
    }

    notifyComplete(result, dataSource);

    stage = Stage.ENCODE;
    try {
      if (deferredEncodeManager.hasResourceToEncode()) {
        deferredEncodeManager.encode(diskCacheProvider, options);
      }
    } finally {
      if (lockedResource != null) {
        lockedResource.unlock();
      }
    }
    onEncodeComplete();
  }
  
  private void notifyComplete(Resource<R> resource, DataSource dataSource) {
    setNotifiedOrThrow();
    callback.onResourceReady(resource, dataSource);
  }

由上文可见会在此时调用callback(即EngineJob)的onResourceReady方法。

  @Override
  public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    //对回传的数据进行赋值
    this.resource = resource;
    this.dataSource = dataSource;
    //通过Handle回传调用handleResultOnMainThread,确保该方法运行在UI线程中
    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
  }
  
  @Synthetic
  void handleResultOnMainThread() {
    //省略部分异常判断的代码
    ......
    
    engineResource = engineResourceFactory.build(resource, isCacheable);
    hasResource = true;

    engineResource.acquire();
    listener.onEngineJobComplete(this, key, engineResource);

    //循环触发回调的onResourceReady方法
    for (int i = 0, size = cbs.size(); i < size; i++) {
      ResourceCallback cb = cbs.get(i);
      if (!isInIgnoredCallbacks(cb)) {
        engineResource.acquire();
        cb.onResourceReady(engineResource, dataSource);
      }
    }
    //完成后释放engineResource资源
    engineResource.release();

    release(false /*isRemovedFromQueue*/);
  }

这样就会触发在Engine.load()时传入callback(即SingleRequest)的onResourceReady方法

  @Override
  public void onResourceReady(Resource<?> resource, DataSource dataSource) {
    //省略部分代码
    ......
    onResourceReady((Resource<R>) resource, (R) received, dataSource);
  }
  
  private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
    //省略部分代码
    ......
    
    try {
      if ((requestListener == null
          || !requestListener.onResourceReady(result, model, target, dataSource, isFirstResource))
          && (targetListener == null
          || !targetListener.onResourceReady(result, model, target, dataSource, isFirstResource))) {
        Transition<? super R> animation =
            animationFactory.build(dataSource, isFirstResource);
        //调用target的onResourceReady
        target.onResourceReady(result, animation);
      }
    } finally {
      isCallingCallbacks = false;
    }
    
    //调用requestCoordinator的onRequestSuccess方法
    notifyLoadSuccess();
  }

这里的target我们以上文中的DrawableImageViewTarget为例,先调用它的父类ImageViewTarget的onResourceReady()方法,最终会调用到的DrawableImageViewTarget的setResource()方法中完成资源文件的加载。

  @Override
  protected void setResource(@Nullable Drawable resource) {
    view.setImageDrawable(resource);
  }

总结收获

至此,整个Glide加载图片的主流程分析完成。按照Glide提供的API来划分,整个加载过程分为四步
with()-load()-apply()-into()
这四步的作用分别如下:

  1. with()主要用于初始化Glide,并将对应context进行处理,完成对生命周期的绑定管理。
  2. load()用于对所需加载的资源的model进行识别保存,并且创建RequestBuilder
  3. apply()方法用于对用户设定的RequestOptions通过位运算进行传入赋值。
  4. into()方法才是整个加载过程的核心,实现了缓存加载,解析,转换等过程,最终通过回调将解析处理完成的资源设置到对应的view中
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容