Glide源码解析

Github: Glide
分析版本: 85bf0c3

An image loading and caching library for Android focused on smooth scrolling

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

Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。Glide的Api是如此的灵活,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于 HttpUrlConnection
的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。
虽然Glide 的主要目标是让任何形式的图片列表的滚动尽可能地变得更快、更平滑,但实际上,Glide几乎能满足你对远程图片的拉取/缩放/显示的一切需求。

使用

// For a simple view:
@Override public void onCreate(Bundle savedInstanceState) {
  ...
  ImageView imageView = (ImageView) findViewById(R.id.my_image_view);

  Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
}

更多

Glide Document

源码

Glide#with(…)

with()
在 Glide 类中好几个方法重载,可以接收 Context
Activity
Fragment
等类型参数

public class Glide implements ComponentCallbacks2 {
  // ...
  
  @NonNull
  public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }
  
  @NonNull
  public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
  }

  @NonNull
  public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }
  
  @NonNull
  public static RequestManager with(@NonNull Fragment fragment) {
    return getRetriever(fragment.getContext()).get(fragment);
  }
  
  @Deprecated
  @NonNull
  public static RequestManager with(@NonNull android.app.Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }
  
  @NonNull
  public static RequestManager with(@NonNull View view) {
    return getRetriever(view.getContext()).get(view);
  }
  
  @NonNull
  private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    // Context could be null for other reasons (ie the user passes in null), but in practice it will
    // only occur due to errors with the Fragment lifecycle.
    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();
  }
  
  // ...
}

这些方法都是通过 getRetriever(@Nullable Context context)
方法来获取 RequestManagerRetriever
对象,而其中 Glide.get(context)
进行了初始化等操作

Glide#get(Context context)

public class Glide implements ComponentCallbacks2 {
  // ...
  
  /**
   * Get the singleton.
   *
   * @return the singleton
   */
  @NonNull
  public static Glide get(@NonNull Context context) {
    if (glide == null) {
      GeneratedAppGlideModule annotationGeneratedModule =
          getAnnotationGeneratedGlideModules(context.getApplicationContext());
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context, annotationGeneratedModule);
        }
      }
    }

    return glide;
  }
  
  private static GeneratedAppGlideModule getAnnotationGeneratedGlideModules(Context context) {
    GeneratedAppGlideModule result = null;
    try {
      Class clazz =
          (Class)
              Class.forName("com.bumptech.glide.GeneratedAppGlideModuleImpl");
      result =
          clazz.getDeclaredConstructor(Context.class).newInstance(context.getApplicationContext());
    } catch (ClassNotFoundException e) {
      if (Log.isLoggable(TAG, Log.WARN)) {
        Log.w(
            TAG,
            "Failed to find GeneratedAppGlideModule. You should include an"
                + " annotationProcessor compile dependency on com.github.bumptech.glide:compiler"
                + " in your application and a @GlideModule annotated AppGlideModule implementation"
                + " or LibraryGlideModules will be silently ignored");
      }
      // These exceptions can't be squashed across all versions of Android.
    } catch (InstantiationException e) {
      throwIncorrectGlideModule(e);
    } catch (IllegalAccessException e) {
      throwIncorrectGlideModule(e);
    } catch (NoSuchMethodException e) {
      throwIncorrectGlideModule(e);
    } catch (InvocationTargetException e) {
      throwIncorrectGlideModule(e);
    }
    return result;
  }
  
  @GuardedBy("Glide.class")
  private static void checkAndInitializeGlid                    e(
      @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
    // In the thread running initGlide(), one or more classes may call Glide.get(context).
    // Without this check, those calls could trigger infinite recursion.
    if (isInitializing) {
      throw new IllegalStateException(
          "You cannot call Glide.get() in registerComponents(),"
              + " use the provided Glide instance instead");
    }
    isInitializing = true;
    initializeGlide(context, generatedAppGlideModule);
    isInitializing = false;
  }
  
  // ...
}

com.bumptech.glide.GeneratedAppGlideModuleImpl
会通过 apt 生成,路径为 build⁩/generated⁩/source⁩/apt⁩/debug⁩/com⁩/bumptech⁩/glide⁩/GeneratedAppGlideModuleImpl.java
,该对象中会持有我们进行配置的类( extends AppGlideModule
),若没有在 java 代码中配置或者 isManifestParsingEnabled()
返回的 true
,则会继续从 AndroidManifest 中去读取配置,主要操作都在 initializeGlide()
中进行

RequestManagerRetriever#get(…)

之前说到的可以接收 Context
Activity
Fragment
等类型参数,具体就是在这个进行判断操作

public class RequestManagerRetriever implements Handler.Callback {
  // ...
  
  @NonNull
  public RequestManager get(@NonNull Context context) {
    if (context == null) {
      throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {
      if (context instanceof FragmentActivity) {
        return get((FragmentActivity) context);
      } else if (context instanceof Activity) {
        return get((Activity) context);
      } else if (context instanceof ContextWrapper
          // Only unwrap a ContextWrapper if the baseContext has a non-null application context.
          // Context#createPackageContext may return a Context without an Application instance,
          // in which case a ContextWrapper may be used to attach one.
          && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }

    return getApplicationManager(context);
  }
  
  @NonNull
  public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

  @NonNull
  public RequestManager get(@NonNull Fragment fragment) {
    Preconditions.checkNotNull(
        fragment.getContext(),
        "You cannot start a load on a fragment before it is attached or after it is destroyed");
    if (Util.isOnBackgroundThread()) {
      return get(fragment.getContext().getApplicationContext());
    } else {
      FragmentManager fm = fragment.getChildFragmentManager();
      return supportFragmentGet(fragment.getContext(), fm, fragment, fragment.isVisible());
    }
  }

  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull View view) {
    if (Util.isOnBackgroundThread()) {
      return get(view.getContext().getApplicationContext());
    }

    Preconditions.checkNotNull(view);
    Preconditions.checkNotNull(
        view.getContext(), "Unable to obtain a request manager for a view without a Context");
    Activity activity = findActivity(view.getContext());
    // The view might be somewhere else, like a service.
    if (activity == null) {
      return get(view.getContext().getApplicationContext());
    }

    // Support Fragments.
    // Although the user might have non-support Fragments attached to FragmentActivity, searching
    // for non-support Fragments is so expensive pre O and that should be rare enough that we
    // prefer to just fall back to the Activity directly.
    if (activity instanceof FragmentActivity) {
      Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
      return fragment != null ? get(fragment) : get(activity);
    }

    // Standard Fragments.
    android.app.Fragment fragment = findFragment(view, activity);
    if (fragment == null) {
      return get(activity);
    }
    return get(fragment);
  }
  
  // ...
}

get(Context context)

  1. 非主线程的话,当 Application
    处理,Glide 加载图片的生命周期是和 with 里的参数保持一致,而对于 Application
    类型,只有当应用程序被杀掉的时候,图片加载才会停止
  2. 主线程情况下,对 Context
    进行类型判断,其他类型确定的会对应到重载的方法中

对于其他重载方法:

  1. 进行了线程的判断,若非主线程的话,那么走 get(Context context)
    方法
  2. 若是主线程

    1. Activity
      : 拿到 FragmentManager
      对象,调用 fragmentGet()
      方法
    2. android.app.Fragment
      : 获取对应的 Activity,再走 1 流程
    3. androidx.fragment.app.Fragment
      : 拿到 FragmentManager
      对象,调用 supportFragmentGet()
      方法
    4. FragmentActivity
      : 拿到 FragmentManager
      对象,调用 supportFragmentGet()
      方法
    5. View
      : 通过 View#getContext
      找到 Activity

      1. Activity
        为 null,走 Application
        流程
      2. 是否是 FragmentActivity
        ,是的话走 FragmentActivity
        流程
      3. 通过 Activity
        getFragmentManager()
        判断是否有 android.app.Fragment
        ,有的话走对应流程
      4. 最后走 Activity
        流程

RequestManagerRetriever#fragmentGet(…)

public class RequestManagerRetriever implements Handler.Callback {
    //...
  
  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) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }
  
  private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }
  
  // ...
}

  1. 通过 fm.findFragmentByTag(FRAGMENT_TAG)
    找到 RequestManagerFragment

    pendingRequestManagerFragments
    
  2. 通过 ActivityFragmentLifecycle
    isParentVisible
    来处理生命周期
  3. 添加到 Activity
    FragmentManager
  4. 发送一个 ID_REMOVE_FRAGMENT_MANAGER
    消息,处理逻辑就是删除 pendingRequestManagerFragments
    中 key 为 FragmentManager
    的对象
  5. RequestManagerFragment
    中获取 RequestManager
    ,若没有的话通过 RequestManagerFactory#build()
    的方式创建一个,最后返回

RequestManagerFragment
的作用就是为了方便 Glide 控制生命周期,因为 Fragment 的生命周期和 Activity 是同步的,如果 Activity 被销毁了,那么 Fragment 是可以监听到的,这样 Glide 就可以捕获这个事件并停止图片加载

RequestManager#load(…)

public class RequestManager implements LifecycleListener, ModelTypes<RequestBuilder> {
  // ...
  
  public RequestBuilder load(@Nullable Bitmap bitmap) {
    return asDrawable().load(bitmap);
  }
  
  public RequestBuilder load(@Nullable Drawable drawable) {
    return asDrawable().load(drawable);
  }
  
  public RequestBuilder load(@Nullable String string) {
    return asDrawable().load(string);
  }
  
  public RequestBuilder load(@Nullable Uri uri) {
    return asDrawable().load(uri);
  }
  
  public RequestBuilder load(@Nullable File file) {
    return asDrawable().load(file);
  }
  
  public RequestBuilder load(@RawRes @DrawableRes @Nullable Integer resourceId) {
    return asDrawable().load(resourceId);
  }
  
  public RequestBuilder load(@Nullable URL url) {
    return asDrawable().load(url);
  }

  public RequestBuilder load(@Nullable byte[] model) {
    return asDrawable().load(model);
  }

  public RequestBuilder load(@Nullable Object model) {
    return asDrawable().load(model);
  }
  
  public RequestBuilder asDrawable() {
    return as(Drawable.class);
  }
  
  public  RequestBuilder as(
      @NonNull Class resourceClass) {
    return new RequestBuilder(glide, this, resourceClass, context);
  }
  
  // ...
}

若没有指定类型,则调用的是 load(Object model)
,这里都是通过 asDrawable()
来获取 RequestBuilder
对象,同样除了 asDrawable()
还有其他方法 asBitmap()
asGif()
asFile()
,最终都是调用的 as(Class resourceClass)
方法,该方法通过 Class
的形式忽略掉了具体类型

RequestBuilder#load(…)

public class RequestBuilder extends BaseRequestOptions<RequestBuilder> implements Cloneable, ModelTypes<RequestBuilder> {
    // ...
  
  public RequestBuilder load(@Nullable Drawable drawable) {
    return loadGeneric(drawable).apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
  }
  
  private RequestBuilder loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }
  
  public RequestBuilder apply(@NonNull BaseRequestOptions requestOptions) {
    Preconditions.checkNotNull(requestOptions);
    return super.apply(requestOptions);
  }
  
  // ...
}

RequestBuilder
load()
也有很多重载方法,这里就按 Drawable 类型的来讲; apply()
方法的作用是将 RequestOptions
配置应用到 ReqiestBuilder

RequestManager#into(ImageView view)

public class RequestBuilder extends BaseRequestOptions<RequestBuilder> implements Cloneable, ModelTypes<RequestBuilder> {
    // ...
  
  public ViewTarget into(@NonNull ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    BaseRequestOptions requestOptions = this;
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      // Clone in this method so that if we use this RequestBuilder to load into a View and then
      // into a different target, we don't retain the transformation applied based on the previous
      // View's scale type.
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions = requestOptions.clone().optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions = requestOptions.clone().optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.
      }
    }

    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions,
        Executors.mainThreadExecutor());
  }
  
  // ...
}

该方法返回一个 ViewTarget
对象,会把 ImageView
封装进去,也是在该类里面进行 Drawable 的展示

GlideContext#buildImageViewTarget()

public class GlideContext extends ContextWrapper {
  // ...

  @NonNull
  public  ViewTarget buildImageViewTarget(
      @NonNull ImageView imageView, @NonNull Class transcodeClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
  }
  
  // ...
}

ViewTarget
的创建是通过 ImageViewTargetFactory
工厂来实现的

ImageViewTargetFactory#buildTarget(ImageView view, Class clazz)

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

再来看下 DrawableImageViewTarget

DrawableImageViewTarget

public class DrawableImageViewTarget extends ImageViewTarget {

  public DrawableImageViewTarget(ImageView view) {
    super(view);
  }

  /** @deprecated Use {@link #waitForLayout()} instead. */
  // Public API.
  @SuppressWarnings({"unused", "deprecation"})
  @Deprecated
  public DrawableImageViewTarget(ImageView view, boolean waitForLayout) {
    super(view, waitForLayout);
  }

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

DrawableImageViewTarget
继承于 ImageViewTarget
类,父类实现了 LifecycleListener
接口,在不同的生命周期中做不动的事情,比如在 onLoadStarted()
时给 ImageView 塞 placeHolder 的 Drawable,在 onLoadFailed
时给 ImageView 塞 error 的 Drawable

RequestManager#into(Y target, RequestListener targetListener, BaseRequestOptions options, Executor callbackExecutor)

public class RequestBuilder extends BaseRequestOptions<RequestBuilder> implements Cloneable, ModelTypes<RequestBuilder> {
    // ...
  
  private <Y extends Target> Y into(
      @NonNull Y target,
      @Nullable RequestListener targetListener,
      BaseRequestOptions options,
      Executor callbackExecutor) {
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    Request request = buildRequest(target, targetListener, options, callbackExecutor);

    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      request.recycle();
      // If the request is completed, beginning again will ensure the result is re-delivered,
      // triggering RequestListeners and Targets. If the request is failed, beginning again will
      // restart the request, giving it another chance to complete. If the request is already
      // running, we can let it continue running without interruption.
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        // Use the previous request rather than the new one to allow for optimizations like skipping
        // setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
        // that are done in the individual Request.
        previous.begin();
      }
      return target;
    }

    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
  }
  
  // ...
}

  1. 通过 buildRequest(target, targetListener, options, callbackExecutor)
    获取请求的 Request
  2. target.getRequest()
    判断这个 ViewTarger
    是否已经有了 Request
  3. 若为等效 Request
    、MemoryCache 不为 skipMemoryCache
    、已经完成,将当前新生成的 Request 进行回收、释放资源,老 Request
    调用 begin()
    方法
  4. 没有 Request
    或者不满足条件的话,将其设置给 ViewTarget
    ,通过 RequestManager#track
    进行下一步操作

RequestManager#track(Target target, Request request)

public class RequestManager implements LifecycleListener, ModelTypes<RequestBuilder> {
  // ...
  
  synchronized void track(@NonNull Target target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }
  
  // ...
}

runRequest
是请求的开始

RequestTracker#(Request request)

public class RequestTracker {
  // ...
  
  public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }
  
  // ...
}

又走到了 request.begin()

SingleRequest#begin()

public final class SingleRequest implements Request, SizeReadyCallback, ResourceCallback, FactoryPools.Poolable {
  // ...
  
  @Override
  public synchronized void begin() {
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();
    if (model == null) {
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        width = overrideWidth;
        height = overrideHeight;
      }
      // Only log at more verbose log levels if the user has set a fallback drawable, because
      // fallback Drawables indicate the user expects null models occasionally.
      int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
      onLoadFailed(new GlideException("Received null model"), logLevel);
      return;
    }

    if (status == Status.RUNNING) {
      throw new IllegalArgumentException("Cannot restart a running request");
    }

    // If we're restarted after we're complete (usually via something like a notifyDataSetChanged
    // that starts an identical request into the same Target or View), we can simply use the
    // resource and size we retrieved the last time around and skip obtaining a new size, starting a
    // new load etc. This does mean that users who want to restart a load because they expect that
    // the view size has changed will need to explicitly clear the View or Target before starting
    // the new load.
    if (status == Status.COMPLETE) {
      onResourceReady(resource, DataSource.MEMORY_CACHE);
      return;
    }

    // Restarts for requests that are neither complete nor running can be treated as new requests
    // and can run again from the beginning.

    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      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));
    }
  }
  
  public synchronized void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    if (IS_VERBOSE_LOGGABLE) {
      logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
    if (status != Status.WAITING_FOR_SIZE) {
      return;
    }
    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));
    }
    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);

    // 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));
    }
  }
  
  // ...
}

  1. 判断宽高是否有效,若无效则调用 onLoadFailed()
    ,然后 return
  2. 当前状态为 Status.RUNNING
    的话,抛异常
  3. 当前状态为 Status.COMPLETE
    的话,调用 onResourceReady()
    ,将 resource 通过 RequestListener
    onResourceReady()
    返回出去,然后 return
  4. 将当前状态设置成 Status.WAITING_FOR_SIZE
  5. 若当前宽高又明确的值的话,调用 onSizeReady()
    进行下一步操作,同时将状态变为 Status.RUNNING
    ;没有的话调用 target.getSize(SizeReadyCallback)
    来获取,获取到之后通过 SizeReadyCallback
    回调返回 (若 View 宽高还未确定的情况下会通过 ViewTreeObserver 的 OnPreDrawListener 来监听)
  6. 当状态为 Status.RUNNING
    或者 status == Status.WAITING_FOR_SIZE
    且有 placeholder 的情况下,调用 target.onLoadStarted(getPlaceholderDrawable())

Engine#load(…)

public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedListener, EngineResource.ResourceListener {
  // ...
  
  public  LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class resourceClass,
      Class 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,
      Executor callbackExecutor) {
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

    EngineKey key =
        keyFactory.buildKey(
            model,
            signature,
            width,
            height,
            transformations,
            resourceClass,
            transcodeClass,
            options);

    EngineResource memoryResource;
    synchronized (this) {
      memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);

      if (memoryResource == null) {
        return waitForExistingOrStartNewJob(
            glideContext,
            model,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            options,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache,
            cb,
            callbackExecutor,
            key,
            startTime);
      }
    }

    // Avoid calling back while holding the engine lock, doing so makes it easier for callers to
    // deadlock.
    cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
    return null;
  }
  
  @Nullable
  private EngineResource loadFromMemory(
      EngineKey key, boolean isMemoryCacheable, long startTime) {
    if (!isMemoryCacheable) {
      return null;
    }

    EngineResource active = loadFromActiveResources(key);
    if (active != null) {
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return active;
    }

    EngineResource cached = loadFromCache(key);
    if (cached != null) {
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return cached;
    }

    return null;
  }
  
  @Nullable
  private EngineResource loadFromActiveResources(Key key) {
    EngineResource active = activeResources.get(key);
    if (active != null) {
      active.acquire();
    }

    return active;
  }
  
  private EngineResource loadFromCache(Key key) {
    EngineResource cached = getEngineResourceFromCache(key);
    if (cached != null) {
      cached.acquire();
      activeResources.activate(key, cached);
    }
    return cached;
  }
  
  private EngineResource getEngineResourceFromCache(Key key) {
    Resource cached = cache.remove(key);

    final EngineResource result;
    if (cached == null) {
      result = null;
    } else if (cached instanceof EngineResource) {
      // Save an object allocation if we've cached an EngineResource (the typical case).
      result = (EngineResource) cached;
    } else {
      result =
          new EngineResource(
              cached, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ true, key, /*listener=*/ this);
    }
    return result;
  }
  
  // ...
}

  1. 构建 EngineKey
  2. 调用 loadFromMemory()
    尝试从缓存中获取

    1. 通过 loadFromActiveResources()
      ActiveResources
      中获取,这里在内存存了一个 Map
    2. 若找不到,接着通过 loadFromCache()
      MemoryCache
      获取,该对象可配置,如获取到则在 activeResources
      中放一份
  3. 没有缓存的话,通过 waitForExistingOrStartNewJob()
    去请求

Engine#waitForExistingOrStartNewJob(…)

public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedListener, EngineResource.ResourceListener {
  // ...

  private  LoadStatus waitForExistingOrStartNewJob(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class resourceClass,
      Class 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,
      Executor callbackExecutor,
      EngineKey key,
      long startTime) {

    EngineJob current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
      current.addCallback(cb, callbackExecutor);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }

    EngineJob engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);

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

    jobs.put(key, engineJob);

    engineJob.addCallback(cb, callbackExecutor);
    engineJob.start(decodeJob);

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

  1. 通过 jobs.get()
    来判断是否已经在队列里面了,若在的话再添加个 callback 然后 return
  2. 通过 EngineJobFactory
    构建一个 EngineJob
    ,通过 DecodeJobFactory
    构建一个 DecodeJob
    ,放入到 Jobs
  3. 通过 EngineJob#start()
    开始请求

EngineJob#start(DecodeJob decodeJob)

class EngineJob implements DecodeJob.Callback, Poolable {
  // ...
  
  public synchronized void start(DecodeJob decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor =
        decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }
  
  // ...
}

判断是否从缓存中获取,然后拿到对应的线程池执行 DecodeJob

DecodeJob#run()

class DecodeJob implements DataFetcherGenerator.FetcherReadyCallback, Runnable, Comparable<DecodeJob>, Poolable {
  // ...
  
  @Override
  public void run() {
    // This should be much more fine grained, but since Java's thread pool implementation silently
    // swallows all otherwise fatal exceptions, this will at least make it obvious to developers
    // that something is failing.
    GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
    // Methods in the try statement can invalidate currentFetcher, so set a local variable here to
    // ensure that the fetcher is cleaned up either way.
    DataFetcher localFetcher = currentFetcher;
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      runWrapped();
    } catch (CallbackException e) {
      // If a callback not controlled by Glide throws an exception, we should avoid the Glide
      // specific debug logic below.
      throw e;
    } catch (Throwable t) {
      // Catch Throwable and not Exception to handle OOMs. Throwables are swallowed by our
      // usage of .submit() in GlideExecutor so we're not silently hiding crashes by doing this. We
      // are however ensuring that our callbacks are always notified when a load fails. Without this
      // notification, uncaught throwables never notify the corresponding callbacks, which can cause
      // loads to silently hang forever, a case that's especially bad for users using Futures on
      // background threads.
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(
            TAG,
            "DecodeJob threw unexpectedly" + ", isCancelled: " + isCancelled + ", stage: " + stage,
            t);
      }
      // When we're encoding we've already notified our callback and it isn't safe to do so again.
      if (stage != Stage.ENCODE) {
        throwables.add(t);
        notifyFailed();
      }
      if (!isCancelled) {
        throw t;
      }
      throw t;
    } finally {
      // Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call
      // close in all cases anyway.
      if (localFetcher != null) {
        localFetcher.cleanup();
      }
      GlideTrace.endSection();
    }
  }
  
  private void runWrapped() {
    switch (runReason) {
      case INITIALIZE:
        stage = getNextStage(Stage.INITIALIZE);
        currentGenerator = getNextGenerator();
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }
  
  private Stage getNextStage(Stage current) {
    switch (current) {
      case INITIALIZE:
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE
            : getNextStage(Stage.RESOURCE_CACHE);
      case RESOURCE_CACHE:
        return diskCacheStrategy.decodeCachedData()
            ? Stage.DATA_CACHE
            : getNextStage(Stage.DATA_CACHE);
      case DATA_CACHE:
        // Skip loading from source if the user opted to only retrieve the resource from cache.
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
  }
  
  private DataFetcherGenerator getNextGenerator() {
    switch (stage) {
      case RESOURCE_CACHE:
        // 产生含有降低采样/转换资源数据缓存文件的 DataFetcher
        return new ResourceCacheGenerator(decodeHelper, this);
      case DATA_CACHE:
        // 产生包含原始未修改的源数据缓存文件的 DataFetcher
        return new DataCacheGenerator(decodeHelper, this);
      case SOURCE:
        // 生成使用注册的 ModelLoader 和加载时提供的 Model 获取源数据规定的 DataFetcher
        // 根据不同的磁盘缓存策略,源数据可首先被写入到磁盘,然后从缓存文件中加载,而不是直接返回
        return new SourceGenerator(decodeHelper, this);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized stage: " + stage);
    }
  }
  
  private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    while (!isCancelled
        && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

      if (stage == Stage.SOURCE) {
        reschedule();
        return;
      }
    }
    // We've run out of stages and generators, give up.
    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
      notifyFailed();
    }

    // Otherwise a generator started a new load and we expect to be called back in
    // onDataFetcherReady.
  }
  
  // ...
}

最开始的状态为 INITIALIZE

  1. getNextStage()
    返回的 Stage
    的作用是标识当前为哪个阶段,不同阶段做不同的事;在还没有缓存情况,这里首先应该做的是加载;所以递归调用这个函数,最终返回的 Stage.SOURCE
  2. getNextGenerator()
    通过 Stage
    找到数据获取生成器
  3. runGenerators()
    去数据获取

SourceGenerator#startNext()

class SourceGenerator implements DataFetcherGenerator, DataFetcher.DataCallback, DataFetcherGenerator.FetcherReadyCallback {
  // ...
  
  @Override
  public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }

    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
      return true;
    }
    sourceCacheGenerator = null;

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
              || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }
  
  // ...
}

然后根据 ModelLoader.LoadData 的 fetcher 加载数据 loadData.fetcher.loadData(helper.getPriority(), this);

HttpUrlFetcher#loadData(Priority priority, DataCallback callback)

public class HttpUrlFetcher implements DataFetcher {
  // ...
  
  @Override
  public void loadData(
      @NonNull Priority priority, @NonNull DataCallback callback) {
    long startTime = LogTime.getLogTime();
    try {
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
      callback.onDataReady(result);
    } catch (IOException e) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "Failed to load data for url", e);
      }
      callback.onLoadFailed(e);
    } finally {
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
      }
    }
  }
  
  private InputStream loadDataWithRedirects(
      URL url, int redirects, URL lastUrl, Map headers) throws IOException {
    if (redirects >= MAXIMUM_REDIRECTS) {
      throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
    } else {
      // Comparing the URLs using .equals performs additional network I/O and is generally broken.
      // See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
      try {
        if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
          throw new HttpException("In re-direct loop");
        }
      } catch (URISyntaxException e) {
        // Do nothing, this is best effort.
      }
    }

    urlConnection = connectionFactory.build(url);
    for (Map.Entry headerEntry : headers.entrySet()) {
      urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
    }
    urlConnection.setConnectTimeout(timeout);
    urlConnection.setReadTimeout(timeout);
    urlConnection.setUseCaches(false);
    urlConnection.setDoInput(true);

    // Stop the urlConnection instance of HttpUrlConnection from following redirects so that
    // redirects will be handled by recursive calls to this method, loadDataWithRedirects.
    urlConnection.setInstanceFollowRedirects(false);

    // Connect explicitly to avoid errors in decoders if connection fails.
    urlConnection.connect();
    // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
    stream = urlConnection.getInputStream();
    if (isCancelled) {
      return null;
    }
    final int statusCode = urlConnection.getResponseCode();
    if (isHttpOk(statusCode)) {
      return getStreamForSuccessfulRequest(urlConnection);
    } else if (isHttpRedirect(statusCode)) {
      String redirectUrlString = urlConnection.getHeaderField("Location");
      if (TextUtils.isEmpty(redirectUrlString)) {
        throw new HttpException("Received empty or null redirect url");
      }
      URL redirectUrl = new URL(url, redirectUrlString);
      // Closing the stream specifically is required to avoid leaking ResponseBodys in addition
      // to disconnecting the url connection below. See #2352.
      cleanup();
      return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
    } else if (statusCode == INVALID_STATUS_CODE) {
      throw new HttpException(statusCode);
    } else {
      throw new HttpException(urlConnection.getResponseMessage(), statusCode);
    }
  }
  
  // ...
}

这里就是网络请求,请求成功后通过 callback.onDataReady(result)
返回出去

SourceGenerator#onDataReady(Object data)

class SourceGenerator implements DataFetcherGenerator, DataFetcher.DataCallback, DataFetcherGenerator.FetcherReadyCallback {
  // ...
  
  @Override
  public void onDataReady(Object data) {
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
    if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      dataToCache = data;
      // We might be being called back on someone else's thread. Before doing anything, we should
      // reschedule to get back onto Glide's thread.
      cb.reschedule();
    } else {
      cb.onDataFetcherReady(
          loadData.sourceKey,
          data,
          loadData.fetcher,
          loadData.fetcher.getDataSource(),
          originalKey);
    }
  }
  
  // ...
}

  1. 若有缓存,则通过 cb.reschedule()
    重新走到 DecodeJob#run()
    方法中(runReason 变为 SWITCH_TO_SOURCE_SERVICE
  2. 没有缓存,则通过 onDataFetcherReady
    走到 DecodeJob#onDataFetcherReady()

DecodeJob#onDataFetcherReady(Key sourceKey, Object data, DataFetcher fetcher, DataSource dataSource, Key attemptedKey)

class DecodeJob implements DataFetcherGenerator.FetcherReadyCallback, Runnable, Comparable<DecodeJob>, Poolable {
  // ...
  
  @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;
    if (Thread.currentThread() != currentThread) {
      runReason = RunReason.DECODE_DATA;
      callback.reschedule(this);
    } else {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        decodeFromRetrievedData();
      } finally {
        GlideTrace.endSection();
      }
    }
  }
  
  private  Resource decodeFromData(
      DataFetcher fetcher, Data data, DataSource dataSource) throws GlideException {
    try {
      if (data == null) {
        return null;
      }
      long startTime = LogTime.getLogTime();
      Resource result = decodeFromFetcher(data, dataSource);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Decoded result " + result, startTime);
      }
      return result;
    } finally {
      fetcher.cleanup();
    }
  }
  
  private  Resource decodeFromFetcher(Data data, DataSource dataSource)
      throws GlideException {
    LoadPath path = decodeHelper.getLoadPath((Class) data.getClass());
    return runLoadPath(data, dataSource, path);
  }
  
  private  Resource runLoadPath(
      Data data, DataSource dataSource, LoadPath path)
      throws GlideException {
    Options options = getOptionsWithHardwareConfig(dataSource);
    DataRewinder rewinder = glideContext.getRegistry().getRewinder(data);
    try {
      // ResourceType in DecodeCallback below is required for compilation to work with gradle.
      return path.load(
          rewinder, options, width, height, new DecodeCallback(dataSource));
    } finally {
      rewinder.cleanup();
    }
  }
  
  // ...
}

  1. 将 runReason 改为 RunReason.DECODE_DATA
    ,若线程不对的话,切线程,重新走到 DecodeJob#run()
    方法中
  2. 通过 decodeFromData()
    解码

LoadPath#load(…)

public class LoadPath {
  // ...
  
  public Resource load(
      DataRewinder rewinder,
      @NonNull Options options,
      int width,
      int height,
      DecodePath.DecodeCallback decodeCallback)
      throws GlideException {
    List throwables = Preconditions.checkNotNull(listPool.acquire());
    try {
      return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
    } finally {
      listPool.release(throwables);
    }
  }
  
  private Resource loadWithExceptionList(
      DataRewinder rewinder,
      @NonNull Options options,
      int width,
      int height,
      DecodePath.DecodeCallback decodeCallback,
      List exceptions)
      throws GlideException {
    Resource result = null;
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = decodePaths.size(); i < size; i++) {
      DecodePath 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;
  }
  
  public Resource decode(
      DataRewinder rewinder,
      int width,
      int height,
      @NonNull Options options,
      DecodeCallback callback)
      throws GlideException {
    Resource decoded = decodeResource(rewinder, width, height, options);
    Resource transformed = callback.onResourceDecoded(decoded);
    return transcoder.transcode(transformed, options);
  }
  
  @NonNull
  private Resource decodeResource(
      DataRewinder rewinder, int width, int height, @NonNull Options options)
      throws GlideException {
    List exceptions = Preconditions.checkNotNull(listPool.acquire());
    try {
      return decodeResourceWithList(rewinder, width, height, options, exceptions);
    } finally {
      listPool.release(exceptions);
    }
  }

  @NonNull
  private Resource decodeResourceWithList(
      DataRewinder rewinder,
      int width,
      int height,
      @NonNull Options options,
      List exceptions)
      throws GlideException {
    Resource result = null;
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = decoders.size(); i < size; i++) {
      ResourceDecoder decoder = decoders.get(i);
      try {
        DataType data = rewinder.rewindAndGet();
        if (decoder.handles(data, options)) {
          data = rewinder.rewindAndGet();
          result = decoder.decode(data, width, height, options);
        }
        // Some decoders throw unexpectedly. If they do, we shouldn't fail the entire load path, but
        // instead log and continue. See #2406 for an example.
      } catch (IOException | RuntimeException | OutOfMemoryError e) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
          Log.v(TAG, "Failed to decode data for " + decoder, e);
        }
        exceptions.add(e);
      }

      if (result != null) {
        break;
      }
    }

    if (result == null) {
      throw new GlideException(failureMessage, new ArrayList(exceptions));
    }
    return result;
  }
  
  // ...
}

最终调用到了 decodeResourceWithList()
方法,通过 decoder.decode(data, width, height, options)
进行解码

BitmapDrawableDecoder#decode(DataType source, int width, int height, Options options)

public class BitmapDrawableDecoder implements ResourceDecoder {
  // ...

  @Override
  public Resource decode(
      @NonNull DataType source, int width, int height, @NonNull Options options)
      throws IOException {
    Resource bitmapResource = decoder.decode(source, width, height, options);
    return LazyBitmapDrawableResource.obtain(resources, bitmapResource);
  }

  // ...
}

这里的 decoder
StreamBitmapDecoder

StreamBitmapDecoder#decode(DataType source, int width, int height, Options options)

public class StreamBitmapDecoder implements ResourceDecoder {
    // ...
  
  @Override
  public Resource decode(
      @NonNull InputStream source, int width, int height, @NonNull Options options)
      throws IOException {

    // Use to fix the mark limit to avoid allocating buffers that fit entire images.
    final RecyclableBufferedInputStream bufferedStream;
    final boolean ownsBufferedStream;
    if (source instanceof RecyclableBufferedInputStream) {
      bufferedStream = (RecyclableBufferedInputStream) source;
      ownsBufferedStream = false;
    } else {
      bufferedStream = new RecyclableBufferedInputStream(source, byteArrayPool);
      ownsBufferedStream = true;
    }

    // Use to retrieve exceptions thrown while reading.
    // TODO(#126): when the framework no longer returns partially decoded Bitmaps or provides a
    // way to determine if a Bitmap is partially decoded, consider removing.
    ExceptionCatchingInputStream exceptionStream =
        ExceptionCatchingInputStream.obtain(bufferedStream);

    // Use to read data.
    // Ensures that we can always reset after reading an image header so that we can still
    // attempt to decode the full image even when the header decode fails and/or overflows our read
    // buffer. See #283.
    MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream);
    UntrustedCallbacks callbacks = new UntrustedCallbacks(bufferedStream, exceptionStream);
    try {
      return downsampler.decode(invalidatingStream, width, height, options, callbacks);
    } finally {
      exceptionStream.release();
      if (ownsBufferedStream) {
        bufferedStream.release();
      }
    }
  }
  
  // ...
}

最后调用到的是 downsampler
decode()

Downsampler#decode(InputStream is, int requestedWidth, int requestedHeight, Options options, DecodeCallbacks callbacks)

public final class Downsampler {
  // ...

  public Resource decode(
      InputStream is,
      int requestedWidth,
      int requestedHeight,
      Options options,
      DecodeCallbacks callbacks)
      throws IOException {
    Preconditions.checkArgument(
        is.markSupported(), "You must provide an InputStream that supports" + " mark()");

    byte[] bytesForOptions = byteArrayPool.get(ArrayPool.STANDARD_BUFFER_SIZE_BYTES, byte[].class);
    BitmapFactory.Options bitmapFactoryOptions = getDefaultOptions();
    bitmapFactoryOptions.inTempStorage = bytesForOptions;

    DecodeFormat decodeFormat = options.get(DECODE_FORMAT);
    PreferredColorSpace preferredColorSpace = options.get(PREFERRED_COLOR_SPACE);
    DownsampleStrategy downsampleStrategy = options.get(DownsampleStrategy.OPTION);
    boolean fixBitmapToRequestedDimensions = options.get(FIX_BITMAP_SIZE_TO_REQUESTED_DIMENSIONS);
    boolean isHardwareConfigAllowed =
        options.get(ALLOW_HARDWARE_CONFIG) != null && options.get(ALLOW_HARDWARE_CONFIG);

    try {
      Bitmap result =
          decodeFromWrappedStreams(
              is,
              bitmapFactoryOptions,
              downsampleStrategy,
              decodeFormat,
              preferredColorSpace,
              isHardwareConfigAllowed,
              requestedWidth,
              requestedHeight,
              fixBitmapToRequestedDimensions,
              callbacks);
      return BitmapResource.obtain(result, bitmapPool);
    } finally {
      releaseOptions(bitmapFactoryOptions);
      byteArrayPool.put(bytesForOptions);
    }
  }
  
  // ...
}

通过 decodeFromWrappedStreams()
解出 Bitmap,然后封装成 BitmapResource

DecodeJob#decodeFromRetrievedData()

class DecodeJob implements DataFetcherGenerator.FetcherReadyCallback, Runnable, Comparable<DecodeJob>, Poolable {
  // ...

  private void decodeFromRetrievedData() {
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logWithTimeAndKey(
          "Retrieved data",
          startFetchTime,
          "data: "
              + currentData
              + ", cache key: "
              + currentSourceKey
              + ", fetcher: "
              + currentFetcher);
    }
    Resource resource = null;
    try {
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }
  

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

    Resource result = resource;
    LockedResource 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();
      }
    }
    // Call onEncodeComplete outside the finally block so that it's not called if the encode process
    // throws.
    onEncodeComplete();
  }
  
  private void notifyComplete(Resource resource, DataSource dataSource) {
    setNotifiedOrThrow();
    callback.onResourceReady(resource, dataSource);
  }
  
  interface Callback {

    void onResourceReady(Resource resource, DataSource dataSource);

    void onLoadFailed(GlideException e);

    void reschedule(DecodeJob job);
  }
  
  // ...
}

重新回到 decodeFromRetrievedData()
方法中,通过 decodeFromData()
获取到 resource 之后通过 notifyEncodeAndRelease()
回调出去

EngineJob#onResourceReady(Resource resource, DataSource dataSource)

class EngineJob implements DecodeJob.Callback, Poolable {
  // ...
  
  @Override
  public void onResourceReady(Resource resource, DataSource dataSource) {
    synchronized (this) {
      this.resource = resource;
      this.dataSource = dataSource;
    }
    notifyCallbacksOfResult();
  }
  
    void notifyCallbacksOfResult() {
    ResourceCallbacksAndExecutors copy;
    Key localKey;
    EngineResource localResource;
    synchronized (this) {
      stateVerifier.throwIfRecycled();
      if (isCancelled) {
        // TODO: Seems like we might as well put this in the memory cache instead of just recycling
        // it since we've gotten this far...
        resource.recycle();
        release();
        return;
      } else if (cbs.isEmpty()) {
        throw new IllegalStateException("Received a resource without any callbacks to notify");
      } else if (hasResource) {
        throw new IllegalStateException("Already have resource");
      }
      engineResource = engineResourceFactory.build(resource, isCacheable, key, resourceListener);
      // Hold on to resource for duration of our callbacks below so we don't recycle it in the
      // middle of notifying if it synchronously released by one of the callbacks. Acquire it under
      // a lock here so that any newly added callback that executes before the next locked section
      // below can't recycle the resource before we call the callbacks.
      hasResource = true;
      copy = cbs.copy();
      incrementPendingCallbacks(copy.size() + 1);

      localKey = key;
      localResource = engineResource;
    }

    engineJobListener.onEngineJobComplete(this, localKey, localResource);

    for (final ResourceCallbackAndExecutor entry : copy) {
      entry.executor.execute(new CallResourceReady(entry.cb));
    }
    decrementPendingCallbacks();
  }
  
    private class CallResourceReady implements Runnable {

    private final ResourceCallback cb;

    CallResourceReady(ResourceCallback cb) {
      this.cb = cb;
    }

    @Override
    public void run() {
      // Make sure we always acquire the request lock, then the EngineJob lock to avoid deadlock
      // (b/136032534).
      synchronized (cb) {
        synchronized (EngineJob.this) {
          if (cbs.contains(cb)) {
            // Acquire for this particular callback.
            engineResource.acquire();
            callCallbackOnResourceReady(cb);
            removeCallback(cb);
          }
          decrementPendingCallbacks();
        }
      }
    }
  }
  
  void callCallbackOnResourceReady(ResourceCallback cb) {
    try {
      // This is overly broad, some Glide code is actually called here, but it's much
      // simpler to encapsulate here than to do so at the actual call point in the
      // Request implementation.
      cb.onResourceReady(engineResource, dataSource);
    } catch (Throwable t) {
      throw new CallbackException(t);
    }
  }
  
  // ...
}

最后通过 cb.onResourceReady(engineResource, dataSource)
回调出去

SingleRequest#onResourceReady(Resource resource, DataSource dataSource)

public final class SingleRequest implements Request, SizeReadyCallback, ResourceCallback, FactoryPools.Poolable {
  // ...
  
  public synchronized void onResourceReady(Resource resource, DataSource dataSource) {
    Resource toRelease = null;
    try {
      synchronized (this) {
        stateVerifier.throwIfRecycled();
        loadStatus = null;
        if (resource == null) {
          GlideException exception =
              new GlideException(
                  "Expected to receive a Resource with an "
                      + "object of "
                      + transcodeClass
                      + " inside, but instead got null.");
          onLoadFailed(exception);
          return;
        }

        Object received = resource.get();
        if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
          toRelease = resource;
          this.resource = null;
          GlideException exception =
              new GlideException(
                  "Expected to receive an object of "
                      + transcodeClass
                      + " but instead"
                      + " got "
                      + (received != null ? received.getClass() : "")
                      + "{"
                      + received
                      + "} inside"
                      + " "
                      + "Resource{"
                      + resource
                      + "}."
                      + (received != null
                          ? ""
                          : " "
                              + "To indicate failure return a null Resource "
                              + "object, rather than a Resource object containing null data."));
          onLoadFailed(exception);
          return;
        }

        if (!canSetResource()) {
          toRelease = resource;
          this.resource = null;
          // We can't put the status to complete before asking canSetResource().
          status = Status.COMPLETE;
          return;
        }

        onResourceReady((Resource) resource, (R) received, dataSource);
      }
    } finally {
      if (toRelease != null) {
        engine.release(toRelease);
      }
    }
  }
  
  private synchronized void onResourceReady(Resource resource, R result, DataSource dataSource) {
    // We must call isFirstReadyResource before setting status.
    boolean isFirstResource = isFirstReadyResource();
    status = Status.COMPLETE;
    this.resource = resource;

    if (glideContext.getLogLevel() <= Log.DEBUG) {
      Log.d(
          GLIDE_TAG,
          "Finished loading "
              + result.getClass().getSimpleName()
              + " from "
              + dataSource
              + " for "
              + model
              + " with size ["
              + width
              + "x"
              + height
              + "] in "
              + LogTime.getElapsedMillis(startTime)
              + " ms");
    }

    isCallingCallbacks = true;
    try {
      boolean anyListenerHandledUpdatingTarget = false;
      if (requestListeners != null) {
        for (RequestListener listener : requestListeners) {
          anyListenerHandledUpdatingTarget |=
              listener.onResourceReady(result, model, target, dataSource, isFirstResource);
        }
      }
      anyListenerHandledUpdatingTarget |=
          targetListener != null
              && targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);

      if (!anyListenerHandledUpdatingTarget) {
        Transition animation = animationFactory.build(dataSource, isFirstResource);
        target.onResourceReady(result, animation);
      }
    } finally {
      isCallingCallbacks = false;
    }

    notifyLoadSuccess();
  }
  
  
  // ...
}

回调的是第一个 onResourceReady()
方法,我们可以看到 Object received = resource.get()
获得了我们刚才封装的 BitmapDrawable 对象;然后将这个值传入到了第二个 onResourceReady()
方法当中,并调用了 target.onResourceReady(result, animation)

ImageViewTarget#onResourceReady(Z resource, Transition transition)

public abstract class ImageViewTarget extends ViewTarget implements Transition.ViewAdapter {
  // ...
  
  @Override
  public void onResourceReady(@NonNull Z resource, @Nullable Transition transition) {
    if (transition == null || !transition.transition(resource, this)) {
      setResourceInternal(resource);
    } else {
      maybeUpdateAnimatable(resource);
    }
  }
  
  private void setResourceInternal(@Nullable Z resource) {
    // Order matters here. Set the resource first to make sure that the Drawable has a valid and
    // non-null Callback before starting it.
    setResource(resource);
    maybeUpdateAnimatable(resource);
  }
  
  protected abstract void setResource(@Nullable Z resource);
  
  // ...
}

DrawableImageViewTarget#setResource(Drawable resource)

public class DrawableImageViewTarget extends ImageViewTarget {

  public DrawableImageViewTarget(ImageView view) {
    super(view);
  }

  /** @deprecated Use {@link #waitForLayout()} instead. */
  // Public API.
  @SuppressWarnings({"unused", "deprecation"})
  @Deprecated
  public DrawableImageViewTarget(ImageView view, boolean waitForLayout) {
    super(view, waitForLayout);
  }

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

在这里把 drawable 塞给了 ImageView