我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android图片加载框架最新解析:从源码的角度理解Glide的执行流程

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android图片加载框架最新解析:从源码的角度理解Glide的执行流程

文章目录准备源码开始阅读1、with()2、load()3、into()总结
众所周知Glide是Android开发中普遍使用的图片加载框架,功能非常强大,API非常简便,也是Google官方唯一推荐的图片加载框架。
基本用法,本文不再叙述,详情请参阅官方Github主页
一般情况下,我们想在界面上显示一张图片,只需要一行代码即可实现。图下所示:
Glide.with(this).load(url).into(imageView)

看起来是如此的简洁、完美!但你可能不知道Glide在背后做了多么复杂、繁重的工作,才将图片展示到我们面前。本着知其然也要知其所以然,那么今天我们就来揭开Glide神秘的面纱。

准备源码

既然要阅读源码,必须先要把源码下载下来,下载有两种方式:
第一种(推荐):如果项目中已经用到Glide,那么就可以用Android Studio 打开项目,点击Glide的引用直接查看。
第二种:在Glide的Github开源主页下载源码,地址:https://github.com/bumptech/glide
这里推荐第一种,因为使用Android Studio阅读可以进行自由的跳转,方便我们阅读。本文是基于最新的Glide 4.11.0来解析的,随着官方不停的版本迭代,本文也会随着变动不定时更新。读者也可以在下方留言反馈。

开始阅读

问:如何把大象装冰箱里?
答:总共分三步,第一步,Glide.with(this);第二步,load(url);第三步,into(imageView)。
阅读源码的思路是从我们平时使用的语句开始,也就是Glide.with(this)。
在分析的过程中我们不必把源码的每一句都搞懂,那样会把你搞得晕头转向,摸不清思路。因为这些代码都不是一个人写的,同样的功能有多种解决方法。记住我们只需要分析主要的实现逻辑就可以了。
准备好了吗?现在我们开始!

1、with()

with()方法是Glide类中的一组静态方法,有多个重载方法,如下所示:

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);
  }
  @SuppressWarnings("deprecation")
  @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);
  }
  ...
}

可以看到,with()的重载方法非常多,可以传入Context、Activity、Fragment以及View,其中传入android.app.Fragment的方法已经标记为过时,不建议使用了,我们可以传入androidx.fragment.app.Fragment来替代。 每个with()方法中的逻辑都非常简单,都先是调用getRetriever()静态方法传入Context对象获得一个RequestManagerRetriever对象,然后调用RequestManagerRetriever的get()方法获取RequestManager“请求管理器”对象。
先看下getRetriever()方法:

public class Glide implements ComponentCallbacks2 {
	...
	@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();
  }
  @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;
  }
@NonNull
  public RequestManagerRetriever getRequestManagerRetriever() {
    return requestManagerRetriever;
  }
	...
}

通过get()方法中两次判断glide == null,再加上synchronized(),表明这里是一个单例模式,具体的单例细节我们不必深究。这里getRetriever()方法中调用get()方法获取Glide单例对象,然后通过Glide对象获取内部的RequestManagerRetriever对象,RequestManagerRetriever是Glide构造方法中定义的对象。
接下来我们看RequestManagerRetriever的get()方法:

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
          && ((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,  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,  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());
    if (activity == null) {
      return get(view.getContext().getApplicationContext());
    }
    if (activity instanceof FragmentActivity) {
      Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
      return fragment != null ? get(fragment) : get((FragmentActivity) activity);
    }
    android.app.Fragment fragment = findFragment(view, activity);
    if (fragment == null) {
      return get(activity);
    }
    return get(fragment);
  }
...
}

上述代码有很多的get()重载方法,看起来比较复杂,其实梳理一下还是很简单的。不论传入的是Context,还是Fragment等等,实际上只有两种情况而已,即传入Application类型的情况和非Application的情况。
有一点需要说明,通过if (Util.isOnMainThread())判断语句,可以看出,我们如果在非主线程中使用Glide,它都会当成传入Application的情况来处理。

先来看传入Application类型的情况。如果在Glide.with()方法中传入Application对象,这里会调用get(context)中的getApplicationManager(context)方法。如下所示:

public class RequestManagerRetriever implements Handler.Callback {
...
@NonNull
  private RequestManager getApplicationManager(@NonNull Context context) {
    if (applicationManager == null) {
      synchronized (this) {
        if (applicationManager == null) {
          Glide glide = Glide.get(context.getApplicationContext());
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(),
                  new EmptyRequestManagerTreeNode(),
                  context.getApplicationContext());
        }
      }
    }
    return applicationManager;
  }
...
}

由于Glide本身就是和应用程序生命周期同步的,所以这里并不需要做什么特殊处理。应用关闭,Glide加载也会终止。
上面的情况比较简单,我们再来看传非Application的情况。无论传Fragment还是Activity,最终的流程都是向当前的Activity添加一个隐藏的Fragment。使用这样一个小技巧,这样Glide就可以知道Activity的生命周期了,加载图片时,也会随着Activity的生命周期,判断是否继续加载。代码如下所示:

public class RequestManagerRetriever implements Handler.Callback {
...
@NonNull
  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(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;
  }
@NonNull
  private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          current.getGlideLifecycle().onStart();
        }
        pendingSupportRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }
...
}

supportFragmentGet()中调用了getSupportRequestManagerFragment()方法,添加了一个SupportRequestManagerFragment ,SupportRequestManagerFragment 就是一个Fragment。

到这里,with()的源码比较好理解吧,不过越到后面会越复杂,接下来我们开始分析第二步吧!

2、load()

我们都知道Glide支持加载图片URL,或是本地路径等多种数据形式的,由于我们不可能把每种都分析一遍,所以这里只选其中之一加载图片URL的方法来研究。使用第一步with()返回的RequestManager对象调用load()方法,可以看出load()方法是在RequestManager类中,如下所示:

public class RequestManager
    implements ComponentCallbacks2, LifecycleListener, ModelTypes<RequestBuilder> {
...
@NonNull
  @CheckResult
  @Override
  public RequestBuilder load(@Nullable String string) {
    return asDrawable().load(string);
  }
  @NonNull
  @CheckResult
  public RequestBuilder asDrawable() {
    return as(Drawable.class);
  }
  @NonNull
  @CheckResult
  public  RequestBuilder as(
      @NonNull Class resourceClass) {
    return new RequestBuilder(glide, this, resourceClass, context);
  }
...
}

上述代码很简单,在load()方法中就是先创建一个RequestBuilder对象,再调用RequestBuilder中的load()方法。其实此类中的所有load重载方法逻辑都是调用RequestBuilder对象中load()方法,而且返回类型都是RequestBuilder。那为什么RequestBuilder类中还有很多load()重载方法呢?除了保存数据源,其实只是做了一点初始化配置上的不同而已。下面是RequestBuilder中的load()方法:

public class RequestBuilder extends BaseRequestOptions<RequestBuilder>
    implements Cloneable, ModelTypes<RequestBuilder> {
...
@NonNull
  @Override
  @CheckResult
  public RequestBuilder load(@Nullable String string) {
    return loadGeneric(string);
  }
  @NonNull
  private RequestBuilder loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }
...
}

至此,load()的逻辑就是这些,我们拿到RequestBuilder对象后,就可以调用apply()方法设置我们自定义的配置(RequestOptions对象),例如:placeholder(),error(),priority()等等。接下来我们看第三步into()中的逻辑。

3、into()

前面两步真是so easy!现在我们进入Glide加载流程中最复杂的部分看看吧。
代码如下:

public class RequestBuilder extends BaseRequestOptions<RequestBuilder>
    implements Cloneable, ModelTypes<RequestBuilder> {
    ...
	@NonNull
  public ViewTarget into(@NonNull ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);
    BaseRequestOptions requestOptions = this;
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      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),
         null,
        requestOptions,
        Executors.mainThreadExecutor());
  }
  ...
}

前面的一些判断逻辑是关于加载配置的,暂时不用管,我们先来看最后一行,调用glideContext.buildImageViewTarget()方法会构建一个Target对象,Target对象是来展示图片用的,我们跟进去代码如下:

public class GlideContext extends ContextWrapper {
...
@NonNull
  public  ViewTarget buildImageViewTarget(
      @NonNull ImageView imageView, @NonNull Class transcodeClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
  }
...
}
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)");
    }
  }
}

这里又调用了ImageViewTargetFactory类的buildTarget()方法,会根据传入的clazz参数判断是Bitmap就返回BitmapImageViewTarget对象,否则就返回DrawableImageViewTarget对象。至于clazz对象的由来,它是我们在调用asBitmap(),asGif()等方法时 传入的。现在回到into()方法,我们看到又调用了一个into()方法,代码如下:

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)) {
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        previous.begin();
      }
      return target;
    }
    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);
    return target;
  }
  ...
}

这些代码我们只抓核心,第14行buildRequest()构建Request对象,第27行requestManager.track()执行这个Request。
Request是一个非常关键的组件,是用来发出加载图片请求的。我们来看下它是如何构建的:

public class RequestBuilder extends BaseRequestOptions<RequestBuilder>
    implements Cloneable, ModelTypes<RequestBuilder> {
    ...
    private Request buildRequest(
      Target target,
      @Nullable RequestListener targetListener,
      BaseRequestOptions requestOptions,
      Executor callbackExecutor) {
    return buildRequestRecursive(
         new Object(),
        target,
        targetListener,
         null,
        transitionOptions,
        requestOptions.getPriority(),
        requestOptions.getOverrideWidth(),
        requestOptions.getOverrideHeight(),
        requestOptions,
        callbackExecutor);
  }
  private Request buildRequestRecursive(
      Object requestLock,
      Target target,
      @Nullable RequestListener targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      BaseRequestOptions requestOptions,
      Executor callbackExecutor) {
    // Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
    ErrorRequestCoordinator errorRequestCoordinator = null;
    if (errorBuilder != null) {
      errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }
    Request mainRequest =
        buildThumbnailRequestRecursive(
            requestLock,
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions,
            callbackExecutor);
    if (errorRequestCoordinator == null) {
      return mainRequest;
    }
    int errorOverrideWidth = errorBuilder.getOverrideWidth();
    int errorOverrideHeight = errorBuilder.getOverrideHeight();
    if (Util.isValidDimensions(overrideWidth, overrideHeight) && !errorBuilder.isValidOverride()) {
      errorOverrideWidth = requestOptions.getOverrideWidth();
      errorOverrideHeight = requestOptions.getOverrideHeight();
    }
    Request errorRequest =
        errorBuilder.buildRequestRecursive(
            requestLock,
            target,
            targetListener,
            errorRequestCoordinator,
            errorBuilder.transitionOptions,
            errorBuilder.getPriority(),
            errorOverrideWidth,
            errorOverrideHeight,
            errorBuilder,
            callbackExecutor);
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }
private Request obtainRequest(
      Object requestLock,
      Target target,
      RequestListener targetListener,
      BaseRequestOptions requestOptions,
      RequestCoordinator requestCoordinator,
      TransitionOptions transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      Executor callbackExecutor) {
    return SingleRequest.obtain(
        context,
        glideContext,
        requestLock,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory(),
        callbackExecutor);
  }
    ...
}

这里又调用了buildRequestRecursive()方法,代码虽然长,大部分处理了缩略图的和出错的逻辑,主流程和缩略图逻辑在第42行buildThumbnailRequestRecursive()方法中,由于代码较多,这里梳理下,最终调用了第92行SingleRequest.obtain()返回的是一个SingleRequest对象,把加载图的所有配置参数都封装了进去,我们就不跟进去看了。
ok,现在构建了Request对象,那它是怎么执行的呢?回到刚才的into()方法,我们看下requestManager.track()方法:

public class RequestManager{
...
	synchronized void track(@NonNull Target target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(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);
    }
  }
  ...
}

这里主要看track()中的requestTracker.runRequest()方法,这里的逻辑是先判断Glide当前是不是处理暂停状态,如果不是暂停状态就调用Request的begin()方法来执行Request,否则的话就先将Request添加到待执行队列里面,等暂停状态解除了之后再执行。
忽略掉暂停请求的功能,我们重点看下begin()方法。由于request实际上是一个SingleRequest对象,所以我们看下SingleRequest类中的begin()方法:

public final class SingleRequest implements Request, SizeReadyCallback, ResourceCallback {
...
@Override
  public void begin() {
    synchronized (requestLock) {
      assertNotCallingCallbacks();
      stateVerifier.throwIfRecycled();
      startTime = LogTime.getLogTime();
      if (model == null) {
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
          width = overrideWidth;
          height = overrideHeight;
        }
        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 (status == Status.COMPLETE) {
        onResourceReady(resource, DataSource.MEMORY_CACHE);
        return;
      }
      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));
      }
    }
  }
  ...
}

这里有个细节注意一下,如果model == null,也就是我们传的图片URL地址为null,会走onLoadFailed()方法,设置占位图,具体逻辑感兴趣的可以去看下。我们说下正常情况,这里判断了你有没有使用override() API为图片指定固定宽高。如果指定了,就会执行第29行onSizeReady()方法。没指定,就会执行第31行target.getSize()方法。getSize()方法的内部会根据ImageView的layout_width和layout_height值计算出图片应该的宽高。在计算完之后,它也会调用onSizeReady()方法。那么我们看下onSizeReady()方法:

public final class SingleRequest implements Request, SizeReadyCallback, ResourceCallback {
...
@Override
  public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    synchronized (requestLock) {
      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);
      if (status != Status.RUNNING) {
        loadStatus = null;
      }
      if (IS_VERBOSE_LOGGABLE) {
        logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
      }
    }
  }
  ...
}

这里我们主要看onSizeReady()方法中的调用engine.load()方法:

public class Engine{
...
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;
  }
  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);
  }
  ...
}

在load()方法中逻辑是先调用loadFromMemory()从内存获取数据,没有的话再调用waitForExistingOrStartNewJob()方法,关于缓存的逻辑,我们下一篇再学习,先从104行看起,这里构建了一个EngineJob,它的主要作用就是用来开启线程的,为后面的异步加载图片做准备。接着下面构建了DecodeJob对象,它看起来像是用来对图片进行解码的,但实际上它的任务十分繁重。DecodeJob就是一个Runnable对象,下面就调用了engineJob.start()方法,在子线程当中执行DecodeJob。我们来看看DecodeJob中的run()方法执行了什么?

class DecodeJob
    implements DataFetcherGenerator.FetcherReadyCallback,
        Runnable,
        Comparable<DecodeJob>,
        Poolable {
        ...
 @Override
  public void run() {
    GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
    DataFetcher localFetcher = currentFetcher;
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      runWrapped();
    } catch (CallbackException e) {
      throw e;
    } 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;
      }
      throw t;
    } finally {
      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:
        return new ResourceCacheGenerator(decodeHelper, this);
      case DATA_CACHE:
        return new DataCacheGenerator(decodeHelper, this);
      case SOURCE:
        return new SourceGenerator(decodeHelper, this);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized stage: " + stage);
    }
  }
  ...
}

这里主要看run()中的runWrapped()方法,runWrapped()方法的逻辑是判断运行原因,在首次运行时runReason是初始值INITIALIZE,接下来调用getNextStage()获取下一步的状态,getNextStage()方法中会判断是否有缓存数据,具体的缓存逻辑暂不研究,我们先假设没有缓存,这时迭代此方法走RESOURCE_CACHE分支,我们再假设没有缓存,会迭代方法走DATA_CACHE分支,这里onlyRetrieveFromCache表示“仅从缓存里检索数据”,现在Glide还没找到数据,如果为true,流程就会结束,所以我们假设为false,返回Stage.SOURCE状态。然后getNextGenerator()方法,就会走SOURCE分支并返回SourceGenerator对象。我们要记住这时的currentGenerator值是一个SourceGenerator对象。因为下面我们要用到它,我们来看下runGenerators()方法:

class DecodeJob{
...
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();
    }
  }
  ...
}

这里比较绕,while循环里面的getNextStage(),getNextGenerator()我们已经分析过了,这里重点是看下第9行currentGenerator.startNext()方法。我们知道currentGenerator是一个SourceGenerator对象,所以startNext()方法在SourceGenerator类中,代码如下:

class SourceGenerator {
...
@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;
        startNextLoad(loadData);
      }
    }
    return started;
  }
  private void startNextLoad(final LoadData toStart) {
    loadData.fetcher.loadData(
        helper.getPriority(),
        new DataCallback() {
          @Override
          public void onDataReady(@Nullable Object data) {
            if (isCurrentRequest(toStart)) {
              onDataReadyInternal(toStart, data);
            }
          }
          @Override
          public void onLoadFailed(@NonNull Exception e) {
            if (isCurrentRequest(toStart)) {
              onLoadFailedInternal(toStart, e);
            }
          }
        });
  }
  ...
}

可以看到startNext()中又调用了startNextLoad()方法,我重点看第19行和第31行,先说第19行,作用是获取数据加载器,代码如下:

final class DecodeHelper {
...
List<LoadData> getLoadData() {
    if (!isLoadDataSet) {
      isLoadDataSet = true;
      loadData.clear();
      List<ModelLoader> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
      //noinspection ForLoopReplaceableByForEach to improve perf
      for (int i = 0, size = modelLoaders.size(); i < size; i++) {
        ModelLoader modelLoader = modelLoaders.get(i);
        LoadData current = modelLoader.buildLoadData(model, width, height, options);
        if (current != null) {
          loadData.add(current);
        }
      }
    }
    return loadData;
  }
  ...
}

第7行这里从Glide实例的Registry注册表中获取modelLoaders。
注意:在注册表中注册的都是ModelLoader的实现ModelLoaderFactory静态工厂类,当调用Registry的getModelLoaders时会调用工厂类中的build()方法。
因为我们以String为例,所以这里的model是String类型。我们来看String类型有哪些modelLoaders:

public class Glide{
...
Glide(){
	registry
	.append(String.class, InputStream.class, new DataUrlLoader.StreamFactory())
    .append(String.class, InputStream.class, new StringLoader.StreamFactory())
    .append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
    .append(String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory())
}
...
}

这里我们以StringLoader.StreamFactory为例子,调用了getModelLoaders()方法,会执行StringLoader.StreamFactory的build()方法。代码如下:

public class StringLoader{
	public static class StreamFactory{
		@NonNull
    @Override
    public ModelLoader build(@NonNull MultiModelLoaderFactory multiFactory) {
      return new StringLoader(multiFactory.build(Uri.class, InputStream.class));
    }
	}
}

在build()方法中构建了StringLoader对象,里面调用了multiFactory.build()方法,这时我们需要在Glide的registry注册表中找到参数为Uri.class, InputStream.class的Factory对象。这时候的重点是看HttpUriLoader.Factory().build()。

registry
.append(Uri.class, InputStream.class, new HttpUriLoader.Factory())

就这样不断追踪下去最终返回的是HttpGlideUrlLoader对象:

public class HttpGlideUrlLoader{
...
public static class Factory{
@NonNull
    @Override
    public ModelLoader build(MultiModelLoaderFactory multiFactory) {
      return new HttpGlideUrlLoader(modelCache);
    }
}
...
}

接下来我们看看StringLoader构造方法:

public class StringLoader{
...
public StringLoader(ModelLoader uriLoader) {
    this.uriLoader = uriLoader;
  }
  ...
}

就是把HttpGlideUrlLoader对象封装进去,现在我们回到刚才的DecodeHelper.getLoadData()方法,获取完modelLoaders,遍历了一遍并执行modelLoader.buildLoadData()方法构建loadData对象。我们以modelLoader为上面分析的StringLoader对象继续看buildLoadData()的实现:

public class StringLoader{
...
@Override
  public LoadData buildLoadData(
      @NonNull String model, int width, int height, @NonNull Options options) {
    Uri uri = parseUri(model);
    if (uri == null || !uriLoader.handles(uri)) {
      return null;
    }
    return uriLoader.buildLoadData(uri, width, height, options);
  }
...
}

这里调用了uriLoader.buildLoadData(),也就是HttpGlideUrlLoader类中的buildLoadData()方法:

public class HttpGlideUrlLoader{
...
@Override
  public LoadData buildLoadData(
      @NonNull GlideUrl model, int width, int height, @NonNull Options options) {
    // GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time
    // spent parsing urls.
    GlideUrl url = model;
    if (modelCache != null) {
      url = modelCache.get(model, 0, 0);
      if (url == null) {
        modelCache.put(model, 0, 0, model);
        url = model;
      }
    }
    int timeout = options.get(TIMEOUT);
    return new LoadData(url, new HttpUrlFetcher(url, timeout));
  }
  ...
}

可以看到,最后返回的是封装了HttpUrlFetcher的LoadData对象。现在我们回到SourceGenerator的startNextLoad()方法:

class SourceGenerator{
...
private void startNextLoad(final LoadData toStart) {
    loadData.fetcher.loadData(
        helper.getPriority(),
        new DataCallback() {
          @Override
          public void onDataReady(@Nullable Object data) {
            if (isCurrentRequest(toStart)) {
              onDataReadyInternal(toStart, data);
            }
          }
          @Override
          public void onLoadFailed(@NonNull Exception e) {
            if (isCurrentRequest(toStart)) {
              onLoadFailedInternal(toStart, e);
            }
          }
        });
  }
  ...
}

我可以得知loadData的fetcher既是HttpUrlFetcher对象,所以这里调用的loadData()方法是在HttpUrlFetcher类中:

public class HttpUrlFetcher{
...
@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 {
      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);
    urlConnection.setInstanceFollowRedirects(false);
    urlConnection.connect();
    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);
      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);
    }
  }
  ...
}

可以看到,这里的loadData()调用loadDataWithRedirects()方法获取数据流,loadDataWithRedirects方法使用了HttpURLConnection从网络获取数据。我们费了九牛二虎之力终于找到网络请求代码。
现在有了InputStream,还需要把它回调出去,在第9行调用了callback.onDataReady()方法,从上一步的startNextLoad()方法得知调用了SourceGenerator类的onDataReadyInternal()方法,代码如下:

class SourceGenerator{
...
void onDataReadyInternal(LoadData loadData, Object data) {
        DiskCacheStrategy diskCacheStrategy = this.helper.getDiskCacheStrategy();
        if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
            this.dataToCache = data;
            this.cb.reschedule();
        } else {
            this.cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher, loadData.fetcher.getDataSource(), this.originalKey);
        }
    }
    ...
}

这里有个是否要缓存的策略,我们先不缓存直接看onDataFetcherReady()方法,这里的cb对象是在SourceGenerator对象创建时传入的,还记得SourceGenerator对象在什么时候创建的吗?是在DecodeJob运行时调用了getNextGenerator()方法创建的。DecodeJob本身实现了onDataFetcherReady()方法:

class DecodeJob
    implements DataFetcherGenerator.FetcherReadyCallback{
    ...
@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 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();
    }
  }
  ...
}

第18行onDataFetcherReady()中调用了decodeFromRetrievedData()方法解码数据,第39行decodeFromRetrievedData()通过调用decodeFromData()方法解码数据返回Resource对象,然后第45行调用notifyEncodeAndRelease()通知获取数据成功。代码如下:

class DecodeJob{
...
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);
  }
  ...
}

这里notifyEncodeAndRelease()调用了notifyComplete()方法通知完成,notifyComplete()调用callback.onResourceReady()进行回调数据,onResourceReady()在EngineJob类中实现了此方法:

class EngineJob{
...
@Override
  public void onResourceReady(Resource resource, DataSource dataSource) {
    synchronized (this) {
      this.resource = resource;
      this.dataSource = dataSource;
    }
    notifyCallbacksOfResult();
  }
  @Synthetic
  void notifyCallbacksOfResult() {
    ResourceCallbacksAndExecutors copy;
    Key localKey;
    EngineResource localResource;
    synchronized (this) {
      stateVerifier.throwIfRecycled();
      if (isCancelled) {
        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);
      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();
  }
  ...
}

onResourceReady()调用notifyCallbacksOfResult()通知回调结果,notifyCallbacksOfResult()中主要看第40行,执行了一个线程CallResourceReady(),这个线程做了什么呢,我们看它的run()方法:

class EngineJob{
...
@Override
private class CallResourceReady implements Runnable {
    public void run() {
      synchronized (cb.getLock()) {
        synchronized (EngineJob.this) {
          if (cbs.contains(cb)) {
            // Acquire for this particular callback.
            engineResource.acquire();
            callCallbackOnResourceReady(cb);
            removeCallback(cb);
          }
          decrementPendingCallbacks();
        }
      }
    }
}
@Synthetic
  @GuardedBy("this")
  void callCallbackOnResourceReady(ResourceCallback cb) {
    try {
      cb.onResourceReady(engineResource, dataSource);
    } catch (Throwable t) {
      throw new CallbackException(t);
    }
  }
  ...
}

run()中调用了callCallbackOnResourceReady(),然后调用cb.onResourceReady回调数据,cb就是SingleRequest对象,由于代码较多这里直接给出关键代码:

public final class SingleRequest{
...
private void onResourceReady(){
...
target.onResourceReady(result, animation);
...
}
...
}

这里的target就是调用into()方法时构建的DrawableImageViewTarget对象。所以这里就进入了DrawableImageViewTarget父类ImageViewTarget的onResourceReady()方法,再调用DrawableImageViewTarget的setResource()方法,过程方法比较简单就不列了,这里直接给出最终的方法:

public class DrawableImageViewTarget extends ImageViewTarget {
...
  @Override
  protected void setResource(@Nullable Drawable resource) {
    view.setImageDrawable(resource);
  }
}

到此就把获取到的图片数据通过setImageDrawable()方法设置给了imageView控件,把图片展示出来了。

总结

看到这里,是不是感觉晕晕的?Glide帮我们做了非常多的事情,回调数据当然也很深。
真难相信这么短短的一行代码:Glide.with(this).load(url).into(imageView); 竟然如此的复杂,我们还仅仅是对流程简单的分析,我们下一篇再来探索下Glide的缓存机制。

参考资料
郭神 Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程


作者:小石头93


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android图片加载框架最新解析:从源码的角度理解Glide的执行流程

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android图片加载框架最新解析:从源码的角度理解Glide的执行流程

文章目录准备源码开始阅读1、with()2、load()3、into()总结 众所周知Glide是Android开发中普遍使用的图片加载框架,功能非常强大,API非常简便,也是Google官方唯一推荐的图片加载框架。 基本用法,本文不再叙述
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录