yunshuipiao / Potato

Read the fucking source code for the Android interview
Apache License 2.0
80 stars 12 forks source link

Glide:The loading process of the main flow #18

Open yunshuipiao opened 5 years ago

yunshuipiao commented 5 years ago

Glide:The loading process of the main flow

[TOC]

分析来自 glide 4.8.0, 官方 使用文档

Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。

Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。

Glide.with(fragment)
   .load(url)
   .into(imageView);

上面是官网介绍的最简单的用法,本文章就对这个主流程做个简单分析。

.with()

首先来看 with 方法做了什么:

 /*
 * @param context Any context, will not be retained.
 * @return A RequestManager for the top level application that can be used to start a load.
 * @see #with(android.app.Activity)
 * @see #with(android.app.Fragment)
 * @see #with(android.support.v4.app.Fragment)
 * @see #with(android.support.v4.app.FragmentActivity)
 */
@NonNull
public static RequestManager with(@NonNull Context context) {
  return getRetriever(context).get(context);
}

 @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();
  }

with 有多个重载方法,最终都会调用上述方法, 最终返回一个 RequestManager 对象。这里传入的 context 必须要绑定 view,或者 fragment.getActivity() 不等于 null 。

@NonNull
public static Glide get(@NonNull Context context) {
  if (glide == null) {
    synchronized (Glide.class) {
      if (glide == null) {
        // 初始化 glide
        checkAndInitializeGlide(context);
      }
    }
  }
  return glide;
}

  private static void checkAndInitializeGlide(@NonNull Context context) {
    // 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);
    isInitializing = false;
  }

下面重点来看一下 初始化方法中具体做了什么:

private static void initializeGlide(@NonNull Context context) {
  initializeGlide(context, new GlideBuilder());
}

/**
 * A builder class for setting default structural classes for Glide to use.
 * 建造者模式创建 Glide
 */
public final class GlideBuilder {
  // 过渡方式
  private final Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions = new ArrayMap<>();
  // 负责加载和管理活跃和缓存的资源
  private Engine engine;
  // 重用的 bitmap 资源池
  private BitmapPool bitmapPool;
  // 不同数组类型的资源池
  private ArrayPool arrayPool;
  //    内存缓存
  private MemoryCache memoryCache;
  // 线程池,执行任务
  private GlideExecutor sourceExecutor;
  // 线程池,磁盘缓存
  private GlideExecutor diskCacheExecutor;
  // 懒加载创建磁盘缓存
  private DiskCache.Factory diskCacheFactory;
  // 缓存大小计算
  private MemorySizeCalculator memorySizeCalculator;
  // 网络连接监视器
  private ConnectivityMonitorFactory connectivityMonitorFactory;
  private int logLevel = Log.INFO;
  // 自定义独立的请求选项,常用
  private RequestOptions defaultRequestOptions = new RequestOptions();
  @Nullable
  // 创建 requestManager
  private RequestManagerFactory requestManagerFactory;
  private GlideExecutor animationExecutor;
  private boolean isActiveResourceRetentionAllowed;
  @Nullable
  // 当图片记载时,监测请求状态
  private List<RequestListener<Object>> defaultRequestListeners;
  private boolean isLoggingRequestOriginsEnabled;
  ...
}

所以知道 Glide类中的属性大概有些什么,其中重要的资源池,请求和缓存,后续会介绍。

回到初始化的逻辑,内容有点长,在关键部分做了注释。

private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
  Context applicationContext = context.getApplicationContext();
  // 是否通过注解生成了类: GeneratedAppGlideModuleImpl
  GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
  // 获取 meta 中定义的 GlideModule
  List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
  if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
    manifestModules = new ManifestParser(applicationContext).parse();
  }

  if (annotationGeneratedModule != null
      && !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
    Set<Class<?>> excludedModuleClasses =
        annotationGeneratedModule.getExcludedModuleClasses();
    Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
    while (iterator.hasNext()) {
      com.bumptech.glide.module.GlideModule current = iterator.next();
      if (!excludedModuleClasses.contains(current.getClass())) {
        continue;
      }
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
      }
      iterator.remove();
    }
  }

  if (Log.isLoggable(TAG, Log.DEBUG)) {
    for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
      Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());
    }
  }

  RequestManagerRetriever.RequestManagerFactory factory =
      annotationGeneratedModule != null
          ? annotationGeneratedModule.getRequestManagerFactory() : null;
  builder.setRequestManagerFactory(factory);
  for (com.bumptech.glide.module.GlideModule module : manifestModules) {
    module.applyOptions(applicationContext, builder);
  }
  if (annotationGeneratedModule != null) {
    annotationGeneratedModule.applyOptions(applicationContext, builder);
  }
  // 以上是 Generated API,编译时生成代码的部分,先跳过。

  // 默认值赋值,创建glide
  Glide glide = builder.build(applicationContext);
  for (com.bumptech.glide.module.GlideModule module : manifestModules) {
    try {
      module.registerComponents(applicationContext, glide, glide.registry);
    } catch (AbstractMethodError e) {
      throw new IllegalStateException(
          "Attempting to register a Glide v3 module. If you see this, you or one of your"
              + " dependencies may be including Glide v3 even though you're using Glide v4."
              + " You'll need to find and remove (or update) the offending dependency."
              + " The v3 module name is: " + module.getClass().getName(), e);
    }
  }
  if (annotationGeneratedModule != null) {
    annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
  }
  applicationContext.registerComponentCallbacks(glide);
  Glide.glide = glide;

上面的配置中,MemorySizeCalculator 内存大小的计算比较重要。至此,生成了 glide,用作后续处理的单例。

接着返回一个 requestManagerRetriever, 看一下glide 的属性,大部分都在 builder 中见过。

public class Glide implements ComponentCallbacks2 {
  private static final String DEFAULT_DISK_CACHE_DIR = "image_manager_disk_cache";
  private static final String TAG = "Glide";
  // 唯一单例
  private static volatile Glide glide;
  private static volatile boolean isInitializing;

  private final Engine engine;
  private final BitmapPool bitmapPool;
  private final MemoryCache memoryCache;
  // 提前填充如 bitmappool 的对象
  private final BitmapPreFiller bitmapPreFiller;
  private final GlideContext glideContext;
  // 管理组件注册,以扩展或替换Glide的默认加载、解码和编码逻辑。
  private final Registry registry;
  private final ArrayPool arrayPool;
  // 创建和销毁 RequestManger 的对象
  private final RequestManagerRetriever requestManagerRetriever;
  private final ConnectivityMonitorFactory connectivityMonitorFactory;
  private final List<RequestManager> managers = new ArrayList<>();
  private MemoryCategory memoryCategory = MemoryCategory.NORMAL;
  ...
}

继续往下,getRetriever(context).get(context);然后分别 get 不同对象获取 RequestManager。

@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) {
      return get(((ContextWrapper) context).getBaseContext());
    }
  }

  return getApplicationManager(context);
}
@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) {
        // 创建无UI fragment 管理 glide 的生命周期
        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;
  }

这里创建了一个无UI的SupportRequestManagerFragment, 使其内部的 RequestManager 可以结合生命周期,安全的开始,停止和管理 glide 请求。这种方法在很多地方都有用到,不明白可以继续看一下源码。

小结

在上面的分析中,做的工作主要有:

各种属性的初始化工作,创建 glide 单例 —> 获取请求管理 RequestManager对象, 同时绑定 Lifecycle, start,stop,destory 事件。

有了 RequestManager 对象,那么接下来可以看一下 load 方法做了什么。

.load()

也是有多个重载方法,基本支持所有的图片资源加载,看下面的注释;


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

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

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

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

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

public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
  return asDrawable().load(resourceId);
}

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

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

public RequestBuilder<Drawable> load(@Nullable Object model) {
  return asDrawable().load(model);

通过调用 as(Drawable.class) 将传入的类型 decode 为 Drawable 对象。

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

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

  @SuppressLint("CheckResult")
  @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
  protected RequestBuilder(
      @NonNull Glide glide,
      RequestManager requestManager,
      Class<TranscodeType> transcodeClass,
      Context context) {
    this.glide = glide;
    this.requestManager = requestManager;
    // 转换对象类型
    this.transcodeClass = transcodeClass;
    this.context = context;
    this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
    this.glideContext = glide.getGlideContext();

    // 请求监听器
    initRequestListeners(requestManager.getDefaultRequestListeners());
    apply(requestManager.getDefaultRequestOptions());
  }

下面就开始 进入 load 步骤, 无论调用 load 的哪个重载方法,都会进入下面的代码:

@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
  // 加载对象赋值
  this.model = model;
  isModelSet = true;
  return this;
}

这一步将需要加载的 对象 赋值给RequesBuild 的 model 对象,接着就到了最复杂 into 步骤。

.into()

该方法接收一个 ImageView 对象,将要加载的图片在 view 上显示出来。

加载图片的过程分为几步,下面分别从每一步开始分析。

into() 也是有好几个重载方法,在拿到 ImageView 对象之后,会调用以下方法生成 target 对象,这里就是

DrawableImageViewTarget 对象。

/**
 * A factory responsible for producing the correct type of
 * {@link com.bumptech.glide.request.target.Target} for a given {@link android.view.View} subclass.
 */
public class ImageViewTargetFactory {
  @NonNull
  @SuppressWarnings("unchecked")
  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)");
    }
  }
}

接着经过 into 的几个重载方法,

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 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;

第一阶段

在构建 新的请求中,最后会调用到此方法, 主要的注释如下:

 private Request buildRequestRecursive(
      Target<TranscodeType> target, // 上面提到的加载对象
      @Nullable RequestListener<TranscodeType> targetListener, //记载监听
      @Nullable RequestCoordinator parentCoordinator, // 协调多个请求
      TransitionOptions<?, ? super TranscodeType> 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(parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }

    // 缩略图请求
    Request mainRequest =
        buildThumbnailRequestRecursive(
            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(
            target,
            targetListener,
            errorRequestCoordinator,
            errorBuilder.transitionOptions,
            errorBuilder.getPriority(),
            errorOverrideWidth,
            errorOverrideHeight,
            errorBuilder,
            callbackExecutor);
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }

上面的配置都是 glide 支持的配置,支持 error 图片和 缩略图 显示。同样,主流程没有设置,那么最终 创建一个 SingleRequest 对象。

private Request obtainRequest(...
  ) {
  return SingleRequest.obtain(...
}

到目前有了请求和target ,requestManager.track(target, request); 进行 生命周期管理,以及开始进行请求

  synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }

  /**
   * Starts tracking the given request.
   */
  public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      // singleRequest 开始请求, 见下分析
      request.begin();
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }
@Override
public synchronized void begin() {
  // 进行必要条件验证
  assertNotCallingCallbacks();
  stateVerifier.throwIfRecycled();
  startTime = LogTime.getLogTime();
  // 如果加载资源为空
  if (model == null) {
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      width = overrideWidth;
      height = overrideHeight;
    }
    // 作为备用的 drawable https://muyangmin.github.io/glide-docs-cn/doc/placeholders.html#%E5%90%8E%E5%A4%87%E5%9B%9E%E8%B0%83%E7%AC%A6fallback
    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));
  }
}

当配置的大小确定, 则进入 onSizeReady(), 方法,接着会调用 Engine.load() 方法,返回一个 LoadStatus 对象.

该方法使用给定的参数开始加载,大概的流程如下:

检查当前使用的活跃资源,如果存在则使用;并且将新的不活跃的资源加入内存缓存;

如果内存缓存中存在,是直接使用;

检查正在加载的资源中是否存在,如果存在则返回;

否则开始新的加载。

:这里的活跃资源是指至少提供给一个请求并且还没有为回收的资源。如果所有使用者都释放了资源,将会进入缓存;这时如果从缓存中被重新使用,那么又会加入活跃资源中;如果资源从缓存中移除,那么资源会被重新利用,也可能被丢弃。没有严格要求释放资源,所以活跃的资源都很不稳定。

public synchronized <R> LoadStatus load(
    GlideContext glideContext,
    Object model,
    Key signature, // 签名
    int width,
    int height,
    Class<?> resourceClass,
    Class<R> transcodeClass,
    Priority priority,
    DiskCacheStrategy diskCacheStrategy,  //磁盘缓存策略
    Map<Class<?>, Transformation<?>> transformations,
    boolean isTransformationRequired,
    boolean isScaleOnlyOrNoTransform,
    Options options,
    boolean isMemoryCacheable,
    boolean useUnlimitedSourceExecutorPool,
    boolean useAnimationPool,
    boolean onlyRetrieveFromCache,
    ResourceCallback cb, //加载成功的回调
    Executor callbackExecutor) {
  long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

  // 多个属性生成的,用于存储资源的key值
  EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
      resourceClass, transcodeClass, options);

  EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
  if (active != null) {
     // 从活跃资源中加载
    cb.onResourceReady(active, DataSource.MEMORY_CACHE);
    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Loaded resource from active resources", startTime, key);
    }
    return null;
  }

  EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
  if (cached != null) {
    // 从内存缓存中加载
    cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Loaded resource from cache", startTime, key);
    }
    return null;
  }

  EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
  if (current != null) {
    // 正在有请求加载中
    current.addCallback(cb, callbackExecutor);
    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Added to existing load", startTime, key);
    }
    return new LoadStatus(cb, current);
  }

  // 创建加载请求job
  EngineJob<R> engineJob =
      engineJobFactory.build(
          key,
          isMemoryCacheable,
          useUnlimitedSourceExecutorPool,
          useAnimationPool,
          onlyRetrieveFromCache);

  // 解码资源的 job
  DecodeJob<R> 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);
}

上面方法中涉及两个类,一个是 DecodeJob、一个是 EngineJob。它们之间的关系是,EngineJob 内部维护了线程池,用来管理资源加载,已经当资源加载完毕的时候通知回调。 DecodeJob 继承了 Runnable,是线程池当中的一个任务。就像上面那样,我们通过调用 engineJob.start(decodeJob) 来开始资源加载。

小结

在第一阶段中,整体还是比较清晰。 首先创建的 SingleRequest,然后 RequestMangenr 对 target 和 request 进行管理, 生命周期和加入请求队列;

接着开始 request,会调用 Engine.load() 方法来决定从活跃资源,或者缓存,或者新建 DecodeJob 中加载资源。

第二阶段

decodeJob 将会将会开始执行,并将结果回调给 cb。因为 DecodeJob 继承了 Runnable, 所以会执行其 run 方法。

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

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

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) {
      // 主要过程在上面的 runWrapper(), 这里是为了捕获和处理 OOM 异常,图片操作不可避免。
      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 {
      // 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();
    }

DecodeJob 的执行过程使用了状态模式,它会根据当前的状态决定将要执行的方法。在上面的方法中,当当前任务没有被取消的话,会进入到 runWrapped() 方法。该方法中会使用 runReason作为当前的状态决定要执行的逻辑:

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

这里的 runReason 是一个枚举类型,它包含的枚举值即为上面的三种类型。当我们在一个过程执行完毕之后会回调 DecodeJob 中的方法修改 runReason,然后根据新的状态值执行新的逻辑。

除了 runReasonDecodeJob 中还有一个变量 stage 也是用来决定 DecodeJob 状态的变量。同样,它也是一个枚举,用来表示将要加载数据的数据源以及数据的加载状态。它主要在加载数据的时候在 runGenerators()runWrapped()getNextStage() 三个方法中被修改。通常它的逻辑是,先从(大小、尺寸等)转换之后的缓存中拿数据,如果没有的话再从没有转换过的缓存中拿数据,最后还是拿不到的话就从原始的数据源中加载数据。

以上就是 DecodeJob 中的状态模式运行的原理。

在上面的逻辑中,从 INITIALIZE 状态开始,由于这是没有设计到缓存,所以 得到 SourceGenerator,

currentGenerator.startNext())

@Override
  public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      // 加入cache
      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;
  }

由于这是加载的是网络上的资源,默认情况下会使用 HttpUrlFetcher 下载数据:

public void loadData(@NonNull Priority priority,
    @NonNull DataCallback<? super InputStream> 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<String, String> 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<String, String> 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();
  // 获得流,防止资源泄漏
  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);
  }

小结

这里涉及到 DecodeJob 的执行,和网络的请求过程,代码量相对较大的部分。因此也只是一个简单的分析,多看源码,多思考。下一阶段是将输入流转换成 Drawable。

第三阶段

上面的阶段结束,会回调 onDataReady() 方法:

@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);
  }
}

glide 有默认磁盘缓存策略,所以这里会执行:cb.reschedule();, 最后又回到 DecodeJob 的run 方法。

@Override
public void reschedule() {
  runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
  callback.reschedule(this);
}

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

这里的主要逻辑是构建一个用于将数据缓存到磁盘上面的 DataCacheGeneratorDataCacheGenerator 的流程基本与 SourceGenerator 一致,也就是根据资源文件的类型找到 ModelLoader,然后使用 DataFetcher 加载缓存的资源。与之前不同的是,这次是用 DataFecher 来加载 File 类型的资源。也就是说,当我们从网络中拿到了数据之后 Glide 会先将其缓存到磁盘上面,然后再从磁盘上面读取图片并将其显示到控件上面。所以,当从网络打开了输入流之后 SourceGenerator 的任务基本结束了,而后的显示的任务都由 DataCacheGenerator 来完成。

DataCacheGenerator 中使用 DataUrlLoader.loadData() 后,回调 onDataReady() 方法,接着会调用到:

private void decodeFromRetrievedData() {
  if (Log.isLoggable(TAG, Log.VERBOSE)) {
    logWithTimeAndKey("Retrieved data", startFetchTime,
        "data: " + currentData
            + ", cache key: " + currentSourceKey
            + ", fetcher: " + currentFetcher);
  }
  Resource<R> 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();
  }
}

这一阶段执行完毕,主要是 获取输入流之后的 处理过程,到达下一阶段。

第四阶段

notifyEncodeAndRelease(resource, currentDataSource);

方法一路往下追,最后回到SingleRequest,

private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {

    .......
      .......
      .........
    if (!anyListenerHandledUpdatingTarget) {
      Transition<? super R> animation =
          animationFactory.build(dataSource, isFirstResource);
      // target 加载显示图片
      target.onResourceReady(result, animation);
    }
  } finally {
    isCallingCallbacks = false;
  }

  // 通知结束
  notifyLoadSuccess();
}

然后 回调 ImageViewTarget 的方法, 整个过程结束。

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

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

总结

以上就是Glide.with(fragment).into(ImageView) 的主流程的分析,大致步骤就是初始化glide,创建 RequestManager, 接着创建出加载的类型 RequestBuild<Drawable>model 对象。

into 过程中,主要有以下几步:

第一个阶段是开启 DecodeJob 的过程。DecodeJob 负责从缓存或者从原始的数据源中加载图片资源,对图片进行变换和转码,是 Glide 图片加载过程的核心。DecodeJob 继承了 Runnable,实际进行图片加载的时候会将其放置到线程池当中执行。这个阶段我们重点介绍的是从 RequestBuilder 构建一个 DecodeJob 并开启 DecodeJob 任务的过程。即构建一个 DecodeJob 并将其丢到线程池里的过程。

第二个阶段是打开网络流的过程。这个阶段会根据我们的图片资源来从数据源中加载图片数据。以我们的示例为例,在默认情况下会从网络当中加载图片,并得到一个 InputStream.

第三个阶段是将输入流转换为 Drawable 的过程。得到了 InputStream 之后还要调用 BitmapFactorydecodeStream() 方法来从 InputStream 中得到一个 Drawable.

第四个阶段是将 Drawable 显示到 ImageView 上面的过程。

其中最重要并且最负责的是中间两步,这篇文章只是提了个大概,后续会详细的分析。

当然,关于 Glide 还有很多没有谈到, 包括可配置的 RequestOptions,缓存,注解时生成的部分,希望后面有时间慢慢从用法到源码,慢慢了解吧。

参考文章

官方中文文档翻译

Glide 系列-2:主流程源码分析(4.8.0)