Glide源码分析三

加载图片(解码、转码)

在加载远程图片后,会返回 inputStream ,并会调用 decodeFromRetrievedData 方法进行解码处理。

private void decodeFromRetrievedData() {
  Resource<R> resource = null;
  try {
      // 关键代码,解码数据
    resource = decodeFromData(currentFetcher, currentData, currentDataSource);
  } catch (GlideException e) {
    e.setLoggingDetails(currentAttemptingKey, currentDataSource);
    throwables.add(e);
  }
  if (resource != null) {
      // 处理 resource
    notifyEncodeAndRelease(resource, currentDataSource);
  } else {
    runGenerators();
  }
}

该方法先通过 decodeFromData 方法来获取解码后的数据,然后调用 notifyEncodeAndRelease 方法来通知处理。 decodeFromData 方法里面又会调用 decodeFromFetcher 方法,如下:

private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
    throws GlideException {
    // LoadPath对象其实是根据我们传入的处理数据来返回特定的数据解码转码处理器对象,即用来解码和转码的。
  LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
  return runLoadPath(data, dataSource, path);
}

该方法主要返回一个包装了解码和转码器对象的 LoadPath 对象。具体的解码和转码器对象的类型由我们传入的处理数据类型来通过注册表获取到的。然后会调用 runLoadPath 方法,该方法里面会调用 LoadPath 对象的 load 方法,最后会调用 DecodePathdecode 方法进行解码处理:

// DecodePath.java
public Resource<Transcode> decode(
    DataRewinder<DataType> rewinder,
    int width,
    int height,
    @NonNull Options options,
    DecodeCallback<ResourceType> callback)
    throws GlideException {
    // 调用 decodeResource 进行解码,最终返回可能是 BitmapResource 对象,看具体类型
  Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
    // 这里会回调 DecodeJob 的 onResourceDecoded 方法,最终返回需要转码的类型
  Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
     // 转码 BitmapDrawableTranscoder,最终返回 LazyBitmapDrawableResource
  return transcoder.transcode(transformed, options);
}

该方法分为 3 步来进行:

  1. 调用 decodeResource 方法进行解码处理,因为我们这里需要的是 Drawable 类型,所以这个方法最终会通过 StreamBitmapDecoder 解码器来解码成一个 BitmapResource 对象。
  2. 回调 DecodeJobonResourceDecoded 方法,最终返回需要转码的类型。
  3. 通过 BitmapDrawableTranscoder 对象进行转码处理,最终会返回 LazyBitmapDrawableResource 对象。

对数据进行解码和转码处理后,由上述 decodeFromRetrievedData 方法可知,会调用 notifyEncodeAndRelease 来通知进行编码等处理,该方法里面又会调用 notifyComplete 方法,如下:

private void notifyComplete(Resource<R> resource, DataSource dataSource) {
  setNotifiedOrThrow();
  // 回调 EngineJob 对象的 onResourceReady 
  callback.onResourceReady(resource, dataSource);
}

该方法最后会回调如下代码:

for (final ResourceCallbackAndExecutor entry : copy) {
    // 切换到主线程进行资源回调
  entry.executor.execute(new CallResourceReady(entry.cb));
}

会在主线程回调 CallResourceReady 这个 runnable 对象,最后会回调 SingleRequest 对象的 onResourceReady 方法。

// SingleRequest.java
public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
  stateVerifier.throwIfRecycled();
  loadStatus = null;
  if (resource == null) {
      // 错误回调
    onLoadFailed(exception);
    return;
  }

  // 调用 LazyBitmapDrawableResource 对象 的 get 方法,返回 BitmapDrawable 对象
  Object received = resource.get();
  if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
    releaseResource(resource);
      // 错误回调
    onLoadFailed(exception);
    return;
  }

  if (!canSetResource()) {
    releaseResource(resource);
    status = Status.COMPLETE;
    return;
  }
  // 关键代码
  onResourceReady((Resource<R>) resource, (R) received, dataSource);
}

上述方法如果有数据异常,会回调 onLoadFailed 方法,正常情况下会拿到 BitmapDrawable 对象并传入重载的 onResourceReady 方法。

private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
  boolean isFirstResource = isFirstReadyResource();
  status = Status.COMPLETE;
  this.resource = resource;

  isCallingCallbacks = true;
  try {
    boolean anyListenerHandledUpdatingTarget = false;
       // 回调监听器
    if (requestListeners != null) {
      for (RequestListener<R> listener : requestListeners) {
        anyListenerHandledUpdatingTarget |=
            listener.onResourceReady(result, model, target, dataSource, isFirstResource);
      }
    }
    anyListenerHandledUpdatingTarget |=
        targetListener != null
            && targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);

      // 如果监听器返回的是 true ,后面就不处理了,让用户自己处理
    if (!anyListenerHandledUpdatingTarget) {
      Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
      // 回调 target (DrawableImageViewTarget)的 onResourceReady 方法
      target.onResourceReady(result, animation);
    }
  } finally {
    isCallingCallbacks = false;
  }

  notifyLoadSuccess();
}

上述方法最终会回调 ImageViewTargetonResourceReady 方法,该方法会再调用 ImageViewTarget 对象 setResourceInternal 方法,setResourceInternal 方法最终setResource方法,setResourceImageViewTarget 对象是抽象方法,它在 DrawableImageViewTarget 对象中实现,代码如下:

public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
  if (transition == null || !transition.transition(resource, this)) {
    setResourceInternal(resource);
  } else {
    maybeUpdateAnimatable(resource);
  }
}

private void setResourceInternal(@Nullable Z resource) {
  // 这是一个抽象方法,在 DrawableImageViewTarget 对象中有实现
  setResource(resource);
  maybeUpdateAnimatable(resource);
}

  // DrawableImageViewTarget.java
protected void setResource(@Nullable Drawable resource) {
    // 显示 Drawable 
  view.setImageDrawable(resource);
}

至此,整个加载流程全部分析完毕,我们回过头看一下最初的调用:

Glide.with(this).load(url).into(mImageView);

就这样一行简单的调用,底层做的工作量真的是巨大的。