【笔记整理】Glide 4.9.0 执行流程源码解析

对于源码的分析,是基于 Glide 最简单的使用的流程进行的:

Glide.with(MainActivity.this).load("url of image resource").into(view);
1. with() 方法

with() 方法会传入当前 activityfragment 等,目的就是为了获取对应的 context,然后根据该 context 来得到 RequestManagerRetriever 对象,再进一步得到 RequestManager 对象。并且 Glide 会根据我们传入 with() 方法的参数来确定图片加载的生命周期。

这里,对于 context 只有两种情况,Application 类型的与非 Application 类型的。

对于 Application 类型的,会得到 RequestManagerRetriever#applicationManager(虽然实质上也是 RequestManager 对象,只不过比较特殊一点,因为 Application 对象的生命周期即应用程序的生命周期,因此 Glide 并不需要做什么特殊的处理,它自动就是和应用程序的生命周期是同步的,如果应用程序关闭的话,Glide 的加载也会同时终止)。而非 Applicatuion 类型的则会得到普通的 RequestManager 对象。
在内部,先得到 Glide#requestManagerRetriever,然后通过 requestManagerRetriever#get() 方法得到 RequestManager 对象。

requestManagerRetriever#get() 执行的过程中,会向当前的 Activity 或者 Fragment 添加一个隐藏的 Fragment(名为 SupportRequestManagerFragment 或者 RequestManagerFragment),这个 Fragment 是为了监听 Activity 或者 Fragment 的生命周期,使得能够感知其销毁,从而停止图片的加载。

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

private RequestManager supportFragmentGet(
    @NonNull Context context,
    @NonNull FragmentManager fm,
    @Nullable Fragment parentHint,
    boolean isParentVisible) {
    
  // 进一步调用 getSupportRequestManagerFragment() 来获取 SupportRequestManagerFragment
  SupportRequestManagerFragment current =
      getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
  // 然后得到 SupportRequestManagerFragment 中的 RequestManager 对象(如果为 null 则构建一个并
  // 设置)
  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;
}

// 在 getSupportRequestManagerFragment() 中,会根据 FragmentManager 来得到对应的 
// SupportRequestManagerFragment(如果为 null 则实例化一个并添加)
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);
      // 添加 SupportRequestManagerFragment 
      fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
      handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
    }
  }
  return current;
}

关于 Glide 监听生命周期的解析,传送门

2. load(String) 方法

RequestManager#load(String)

public RequestBuilder<Drawable> load(@Nullable String string) {
  return asDrawable().load(string);
}


public RequestBuilder<Drawable> asDrawable() {
  return as(Drawable.class);
}

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

其中 asDrawable() 最终会构建 RequestBuilder<Drawable> 对象,其中对于 load() 传入 String 类型参数时,RequestBuilder#resourceClassDrawable.classresourceClass 用于指定加载资源被交付的类型。

比如 RequestBuilder<GifDrawable> asGif()RequestBuilder<File> asFile()RequestBuilder<Bitmap> asBitmap() 等等。其中,asDrawable() 是默认的,会根据情况来确定加载的资源被交付时的类型。

然后 load(String) 会进一步调用 RequestBuilder#loadGeneric(),这里只是将传递进来的 url 字符串设置给成员变量 model。

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

因此,load() 主要用于生成一个 RequestBuilder,该对象在后面用于对于资源的请求。

3. into() 方法

经过 Glide.with(Context).load(String) 之后,最终会得到 RequestBuilder<Drawable>,因此 Glide.with(Context).into(ImageView) 实际上就是调用 RequestBuilder<Drawable>#into(ImageView)

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
  Util.assertMainThread();
  Preconditions.checkNotNull(view);
  // RequestBuilder 继承自 BaseRequestOptions
  BaseRequestOptions<?> requestOptions = this;
  
  // 根据 ImageView 的 scaleType 来判断是否克隆并设置额外的 option
  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;
      ...
      default:
        // Do nothing.
    }
  }
  
  // 然后进一步调用冲载的 into() 方法
  return into(
      glideContext.buildImageViewTarget(view, transcodeClass),
      /*targetListener=*/ null,
      requestOptions,
      Executors.mainThreadExecutor());
}

(1)其中 glideContext.buildImageViewTarget(view, transcodeClass) 会构建出一个 ViewTarget<ImageView, X> 对象。这里的 transcodeClass 就是前面在 new RequestBuilder 对象时设置的,即 Drawable.class,且 glideContextGlideContext

// GlideContext.java
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
    @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
  // 进一步调用 ImageViewTargetFactory#buildTarget()
  return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}

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

最终,会得到实际为 DrawableImageViewTargetViewTarget 对象,该对象是用来最终展示图片用的。

(2)进一步调用的 into() 重载方法为:

// RequestBuilder.java

// target 为前面所说的 DrawableImageViewTarget 实例
// targetListener 为 null
// options 是从上一个方法传递过来的
// callbackExecutor 为 Executors.mainThreadExecutor()
private <Y extends Target<TranscodeType>> Y into(
    @NonNull Y target,
    @Nullable RequestListener<TranscodeType> targetListener,
    BaseRequestOptions<?> options,
    Executor callbackExecutor) {
  Preconditions.checkNotNull(target);
  if (!isModelSet) {
    throw new IllegalArgumentException("You must call #load() before calling #into()");
  }
  
  // 根据传递进来的参数构建出 Request
  // 在主流程中,就得到一个 SingleRequest 对象,里面
  Request request = buildRequest(target, targetListener, options, callbackExecutor);
  Request previous = target.getRequest();
  ...
    return target;
  }
  requestManager.clear(target);
  target.setRequest(request);
  // 执行 request
  requestManager.track(target, request);
  return target;
}

requestManager.track(target, request) 中会调用 requestTracker.runRequest(request)

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

先判断 Glide 当前是不是处理暂停状态,如果不是暂停状态就调用 Requestbegin() 方法来执行开启请求,否则的话就先将 Request 添加到待执行队列里面,等暂停状态解除了之后再执行。

正常情况下,Request 的具体类型会是 SingleRequest,因此进入到 SingleRequest#begin()

// SingleRequest.java
public synchronized void begin() {
  assertNotCallingCallbacks();
  stateVerifier.throwIfRecycled();
  startTime = LogTime.getLogTime();
  
  // 如果 model 等于 null,model 也就是我们在第二步 load() 方法中传入的图片 URL 地址,
  // 这个时候会调用 onException() 方法。
  // 在 onException() 中会调用 setErrorPlaceholder()。
  // 而在 setErrorPlaceholder() 根据实际情况来选择调用 fallback()、error()、placeholder() 这几个方法
  // 时设置的图片显示到 ImageView 上
  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;
  }
  ...
  status = Status.WAITING_FOR_SIZE;
  if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
    // 如果使用了 override() API 为图片指定了一个固定的宽高
    onSizeReady(overrideWidth, overrideHeight);
  } else {
  	 // 没有指定则调用 target.getSize()
  	 // target.getSize() 方法的内部会根据 ImageView 的
  	 // layout_width 和 layout_height 值做一系列的计算,来算出图片应该的宽高
  	 // 计算完之后,它也会调用 onSizeReady() 方法
    target.getSize(this);
  }
  ...
}

根据前面的流程,正常情况下都会进入到 onSizeReady() 方法:

public synchronized void onSizeReady(int width, int height) {
  ...
  status = Status.RUNNING;
  float sizeMultiplier = requestOptions.getSizeMultiplier();
  this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
  this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
  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;
  }
}

然后进一步调用 Engine#load(),这一部分就是加载资源的关键了

// Engine.java
public synchronized <R> LoadStatus load(
    ...) {
  long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
  // 首先根据目标资源的相关参数得到对应的 key 值
  EngineKey key = keyFactory.buildKey(model, signature, width, height, transform
      resourceClass, transcodeClass, options);
  // 然后从 ActiveResources 内存缓存中去取
  EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
  // 如果取到了则直接回调后续方法
  if (active != null) {
    cb.onResourceReady(active, DataSource.MEMORY_CACHE);
    return null;
  }
  // 如果在 ActiveResources 内存缓存中没有取到,则再去基于 LruCache 的内存缓存中去取
  EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
  if (cached != null) {
    cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
    return null;
  }
  // 从缓存中查找 key 对应的任务,即加载资源的任务
  EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
  if (current != null) {
    // 如果取到了则表示任务已经完成,进行相应的回调即可
    current.addCallback(cb, callbackExecutor);
    return new LoadStatus(cb, current);
  }
  // 否则,在内存中没有获取到缓存的资源,则构建相关任务,从磁盘或者远程加载
  // 构建一个新的引擎任务
  EngineJob<R> engineJob =
      engineJobFactory.build(
          ...);
  // 构建解码任务
  DecodeJob<R> decodeJob =
      decodeJobFactory.build(
          ...);
  jobs.put(key, engineJob);
  engineJob.addCallback(cb, callbackExecutor);
  engineJob.start(decodeJob);
  return new LoadStatus(cb, engineJob);
}

可以看到,则 Engine#load() 中,会先从内存缓存中去获取目标资源,如果没有,才会进一步去从磁盘缓存或者远程去加载资源(当然,这部分是后面的内容)。

上面说到会构建 EngineJobDecodeJob

其中,EngineJob 对象的主要作用就是用来开启线程的,为后面的异步加载图片做准备。

DecodeJob 对象实现了 Runnable 接口,然后会调用 engineJob.start(decodeJob) 来启动 decodeJob

// EngineJob.java
public synchronized void start(DecodeJob<R> decodeJob) {
  this.decodeJob = decodeJob;
  // 得到对应的 GlideExecutor,用于提交并执行 decodeJob
  GlideExecutor executor = decodeJob.willDecodeFromCache()
      ? diskCacheExecutor
      : getActiveSourceExecutor();
 
  executor.execute(decodeJob);
}

GlideExecutor 有好几种类型的,diskCacheExecutor、sourceExecutor、sourceUnlimitedExecutor、animationExecutor,不同类型的 GlideExecutor 用于从不同的地方 load/decode/transform data,这里的地方指的磁盘缓存、Glide 自己的缓存区等。

不同的 GlideExecutor 对象内部会持有不同的线程池,执行 GlideExecutor#execute(),会间接调用线程池的 execute() 方法。

因此这里可以理解为将 decodeJob 提交到对应的线程池去处理。因为 decodeJobRunnable,当其被处理的时候,实际上会调用其 run() 方法。

// DecodeJob.java
public void run() {
  ...
  // 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();
  } 
  ...
}

private void runWrapped() {
  switch (runReason) {
    case INITIALIZE:
      // 1、得到 stage
      stage = getNextStage(Stage.INITIALIZE);
      // 2、根据 stage 得到对应的 Generator
      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:
      // decodeCachedResource() 为 true 表示尝试 decode 缓存的被转换的图片
      return diskCacheStrategy.decodeCachedResource()
          ? Stage.RESOURCE_CACHE
          : getNextStage(Stage.RESOURCE_CACHE);
    case RESOURCE_CACHE:
      // decodeCachedData() 为 true 表示尝试 decode 缓存的原始图片
      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:
      // 对应被转换的图片的缓存的 Generator
      return new ResourceCacheGenerator(decodeHelper, this);
    case DATA_CACHE:
      // 对应原始图片的缓存的 Generator
      return new DataCacheGenerator(decodeHelper, this);
    case SOURCE:
      // 对应加载的图片的 Generator(此时)
      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
      // currentGenerator 执行加载逻辑
      && !(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.
}

run() 方法中,会进一步调用 runWrapped(),此时会走 case INITIALIZE 的语句。

此时会根据不同的场景的获取不同的 Generator 来获取资源。这里主要针对 SourceGenerator 进行分析,其表示从数据源头请求数据(如通过网路从远程加载)。

(对于 ResourceCacheDataCache,是针对磁盘缓存来说的,因为当资源图片从网络加载后之后,可能会经过一些列的转换,而被转换后的图片资源则对应为 Resource,而没有经过转换的原始图片,则对应为 Source。相关内容在讲关于缓存的章节有说:Glide 4.9.0 的缓存机制

后续的逻辑,主要是在 runGenerators() 中调用 currentGenerator.startNext() 来执行加载逻辑。

// SourceGenerator.java
public boolean startNext() {
  ...
  sourceCacheGenerator = null;
  loadData = null;
  boolean started = false;
  while (!started && hasNextModelLoader()) {
    // 1. 从 DecodeHelper 的数据加载集合中, 获取一个数据加载器
    loadData = helper.getLoadData().get(loadDataListIndex++);
    if (loadData != null
        && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
            || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
      started = true;
      // 2. 使用加载器中 fetcher 执行数据加载
      // 网络的 url 资源对应的就是 HttpGlideUrlLoader,它对应的 ModelLoader.LoadData 中的
      //  fetcher 为 HttpUrlFetcher 类型
      loadData.fetcher.loadData(helper.getPriority(), this);
    }
  }
  return started;
}

对于从网络加载资源,是由 HttpUrlFetcher#loadData() 来处理的。

// HttpUrlFetcher.java
public void loadData(
    @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
  long startTime = LogTime.getLogTime();
  try {
    // 获取网络图片, 内部使用了 HttpURLConnection 实现, 仅仅做了重定向的处理
    InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
    // 回调 callback.onDataReady() 方法将结果回传
    // callback 是在调用方法时传递过来的,这里即 SourceGenerator#startNext() 方法中传递的,即 SourceGenerator 对象自身
    callback.onDataReady(result);
  } catch (IOException e) {
    callback.onLoadFailed(e);
  } finally {
    ...
  }
}

数据加载的过程也是很简单的, HttpUrlFetcher 它使用了 HttpURLConnection 发起了网络请求, 获取了数据流, 至此数据资源的获取就已经完成了, 后面要做的便是最重要的数据处理了, 它通过回调的方式将 InputStream 类型的结果一步一步的进行回调, 最终会回溯到 DecodeJob#onDataFetcherReady 这个方法中。

具体的回调流程,参见:Glide 4.9.0 关于数据加载之后的回调过程

然后,后续的对于原始数据资源的处理,参见:Glide 4.9 源码分析(一) —— 一次完整加载流程 —— 第五点 (由于时间与篇幅原因,暂时不单独进行后续分析)


相关内容索引:
(1)Glide 4.9.0 的缓存机制
(2)Glide 4.9.0 关于数据加载之后的回调过程
(3)Glide 4.9.0 关于监听生命周期


主要参考文章:
1、Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程(郭神的博客,基于 3.7.0 分析的)
2、Glide 源码分析解读-基于最新版Glide 4.9.0
3、Glide 4.9 源码分析(一) —— 一次完整加载流程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值