Glide into(ImageView)源码分析

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

经过 Glide.with(xxx).load(xxx) 之后,最终会得到 RequestBuilder<Drawable>。因此 Glide.with(Context).into(ImageView)最后一步是调用 RequestBuilder的into(ImageView)方法。

1、into(ImageView iv)

@SuppressWarnings({"unused", "WeakerAccess"})
public class RequestBuilder{


  //加载资源到ImageView控件中,取消view对应的其他加载,同时释放已经已经设置到view的资源
  @NonNull
  public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    //设置BaseRequestOptions(请求配置)
    BaseRequestOptions<?> requestOptions = this;
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {

      switch (view.getScaleType()) {
        case CENTER_CROP:
          //
          requestOptions = requestOptions.clone().optionalCenterCrop();
          break;
        ...
        default:
          // Do nothing.
      }
    }

    //glideContext.buildImageViewTarget(view, transcodeClass)
    //会返回一个DrawableImageViewTarget或者BitmapImageViewTarget
    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions,
        Executors.mainThreadExecutor());
  }

  
  private <Y extends Target<TranscodeType>> Y into(...) {
    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 (!Preconditions.checkNotNull(previous).isRunning()) {
        previous.begin();
      }
      return target;
    }

    
    requestManager.clear(target);//清除target中旧的请求
    target.setRequest(request);//给target绑定新的请求
    requestManager.track(target, request);//执行请求

    return target;
  }

  //图片请求不需要内存缓存同时图片控件对应的上一个请求已经完成,则返回true
  private boolean isSkipMemoryCacheWithCompletePreviousRequest(
      BaseRequestOptions<?> options, Request previous) {
    return !options.isMemoryCacheable() && previous.isComplete();
  }

}

into()方法返回参数是ViewTarget,ViewTarget是个抽象类,负责加载Bitmap到View上。

  1. 配置requestOptions的Scaletype类型。
  2. 调用buildRequest方法构建Request,并把Request设置给ViewTarget。
  3. 调用requestManager.track()方法执行请求。

2、buildRequest() 构建请求

这里会涉及到三个request
1、SingleRequest 负责执行请求并将结果反映到 Target 上
2、ErrorRequestCoordinator 负责协调图片请求的Request和请求失败时的errorRequest
3、ThumbnailRequestCoordinator 负责协调原图加载的request和缩略图加载request

2.1 buildRequestRecursive()
public class RequestBuilder {

  //构建Request的入口
  private Request buildRequest(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> requestOptions,
      Executor callbackExecutor) {

    //直接调用buildRequestRecursive,递归调用创建Request 
    return buildRequestRecursive(...);
  }

  //递归调用,这里会分配一般情况下图片请求Request和请求失败的调用的errorRequest
  /**
    * @params targetListener       图片请求回调,可能是null
    * @params transitionOptions  过度动画配置
    * @params priority                  请求的优先级
    * @params overrideWidth       指定图片加载的宽度
    * @params overrideHeight      指定图片加载的高度
    * @params callbackExecutor  线程调度器
    */
  private Request buildRequestRecursive(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,//null
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth, //override(int width, int height)
      int overrideHeight,//override(int width, int height)
      BaseRequestOptions<?> requestOptions
      Executor callbackExecutor) {

    /*  如果调用了error(@Nullable RequestBuilder<TranscodeType> errorBuilder)这个方法,errorBuilder才不为    
     *  空,比如
     *       Glide.with(context)
     *           .load((Object) null)
     *           .error(
     *                Glide.with(context)
     *                .load(errorModel)
     *                .listener(requestListener))
     *           .submit();
    */

    //ErrorRequestCoordinator 主要用来协调图片请求的Request和请求失败时的errorRequest
    ErrorRequestCoordinator errorRequestCoordinator = null;
    if (errorBuilder != null) {
      errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }

    //图片请求的Request,调用buildThumbnailRequestRecursive
    Request mainRequest =
        buildThumbnailRequestRecursive(...);

    if (errorRequestCoordinator == null) {
      return mainRequest;
    }

    ...
    
    //构建图片请求失败时的调用的errorRequest
    Request errorRequest =
        errorBuilder.buildRequestRecursive(...);
    
    //内部协调mainRequest和errorRequest的调用流程
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }
}

第一步判断是否调用了error(@Nullable RequestBuilder<TranscodeType> errorBuilder)这个方法,如果有,则先构建ErrorRequestCoordinator,然后调用buildThumbnailRequestRecursive方法,最后构建errorRequest。

2.2 buildThumbnailRequestRecursive()
//递归调用,这里会分配一般情况下图片请求Request和缩略图请求的thumbnailRequest
private Request buildThumbnailRequestRecursive(...) {
    if (thumbnailBuilder != null) {
      //调用了thumbnail(@Nullable RequestBuilder<TranscodeType> thumbnailRequest) 方法,thumbnailBuilder 才不为空       
      //原图的请求和缩略图的请求可以不是同一张图片,看调用者的设置
     
      ...

      //ThumbnailRequestCoordinator用来协调两个请求,因为有的请求需要同时加载原图和缩略图
      //如果原图已经加载完成,那么缩略图不会再加载
      ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
      //原图的请求
      Request fullRequest =
          obtainRequest(...);
      isThumbnailBuilt = true;

      //缩略图的请求
      Request thumbRequest =
          thumbnailBuilder.buildRequestRecursive(...);

      isThumbnailBuilt = false;
      //配置fullRequest和thumbRequest,内部协调两个请求的调用
      coordinator.setRequests(fullRequest, thumbRequest);
      return coordinator;
    } 
      ...
  }

buildThumbnailRequestRecursive方法构建图片的请求时,会判断是否有调用了thumbnail方法,如果有,就创建ThumbnailRequestCoordinator, 然后创建原图请求和缩略图请求。

2.3 obtainRequest()
  private Request obtainRequest(...) {

    //返回SingleRequest的实例,SingleRequest是Request的子类
    return SingleRequest.obtain(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory(),
        callbackExecutor);
  }

小结:构建Request时,除了构建原图的Request请求之外,还会判断是否需要需要设置errorRequest和thumbnailRequest,然后协调后这个几个请求之间的调用流程, 最后返回的是SingleRequest实例。

2.4、requestManager.track(target, request) 执行图片请求
public class RequestManager implements LifecycleListener,
    ModelTypes<RequestBuilder<Drawable>> {
  
 
  private final RequestTracker requestTracker;
  //RequestTracker用于记录所有的Target, 以及发送生命周期事件
  private final TargetTracker targetTracker = new TargetTracker();


  synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);//添加到TargetTracker的集合中
    requestTracker.runRequest(request);执行请求
  }

}

//用于跟踪进行中请求、取消和重启已完成或已失败的请求
public class RequestTracker {

  //记录所有的request
  private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
  //记录等待执行的request  
  private final List<Request> pendingRequests = new ArrayList<>();
  private boolean isPaused;

  public void runRequest(@NonNull Request request) {
    requests.add(request);
    //判断是否在暂停状态
    if (!isPaused) {
      request.begin();//调用SingleRequest的begin方法
    } else {
      request.clear();//调用SingleRequest的clear方法
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      
      //暂停状态情况下,先记录起等待执行的request
      pendingRequests.add(request);
    }
  }

}

RequestTracker负责跟踪进行中请求、取消和重启已完成或已失败的请求。
requestManager.track(target, request)就是执行图片请求,调用SingleRequest的begin方法

3、SingleRequest#begin()

public final class SingleRequest<R> implements Request,
    SizeReadyCallback,
    ResourceCallback,
    FactoryPools.Poolable {

  //Engine类主要负责启动下载和管理缓存中的和活跃未回收的资源
  private Engine engine;
  private Resource<R> resource;
  private final StateVerifier stateVerifier = StateVerifier.newInstance();

  @Override
  public synchronized void begin() {
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();

    ...

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

    //如果已经下载完成,直接回调onResourceReady,代表加载成功
    if (status == Status.COMPLETE) {
      onResourceReady(resource, DataSource.MEMORY_CACHE);
      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);
    }

    //如果是运行中,或者还在imageView控件的尺寸时
    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
      //回调onLoadStarted的方法,把placeholder()中设置的图片设置给view
      target.onLoadStarted(getPlaceholderDrawable());
    }

    ...
  }

SingleRequest的begin方法中,会进行多个判断,

  • status为COMPLETE就这直接回调onResourceReady方法,
  • status为running就抛出异常,
  • status为WAITING_FOR_SIZE,判断是否调用override方法设置指定宽高,如果指定好了宽高值,直接调用onSizeReady方法;如果没有,调用target的getSize方法获取控件的宽高,ViewTarget以及其子类实现了View 的 OnPreDrawListener接口,View 初始化完成后也会调用 SingleRequest的onSizeReady方法
3.1 onSizeReady()
  /*
   * begin方法中并不会直接发起请求,而是等待 ImageView 初始化完成;
   * 对于 ViewTarget 以及其子类来说,会注册View 的 OnPreDrawListener 事件,
   * 等待 View 初始化完成后就调用onSizeReady方法,才会开始加载图片
   */
  @Override
  public synchronized void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();

    if (status != Status.WAITING_FOR_SIZE) {
      return;
    }
    status = Status.RUNNING;
    float sizeMultiplier = requestOptions.getSizeMultiplier();//获取设置的缩放比例,计算图片请求的宽高
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

    //调用engine的加载方法
    loadStatus =
        engine.load(...);

    ...
  }

}

onSizeReady方法主要就是engine的load方法。

3.2 engine.load()

Engine类负责启动下载和管理活动资源、缓存等等。

/**
  *Engine类主要负责启动下载和管理缓存中的和活跃未回收的资源
  */
public class Engine implements EngineJobListener,
    MemoryCache.ResourceRemovedListener,
    EngineResource.ResourceListener {


  //ActiveResources内部设置了HashMap集合,保存EngineKey到EngineResource(图片资源)的软引用的映射
  private final ActiveResources activeResources;
  //内部的HashMap集合保存EngineKey到EngineJob的映射
  private final Jobs jobs;
  

  /*
   * 构建EngineJob和DecodeJob, 启动DecodeJob
   */
  public synchronized <R> LoadStatus load(...) {
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;


    //buildKey方法是根据图片请求的相关参数生成对应的key
    //EngineKey 用于缓存下载资源的key,对应着一系列的具体的图片请求参数,不同的参数,相同的请求连接对应的key也不一样
    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);

    //从activeResources中的hashmap集合获取EngineResource的弱引用,也就是获取图片资源引用
    //ActiveResources 是Glide的第一级缓存,表示当前正在活动中的资源
    //EngineResource 是Resource接口的实现类,Resource接口包装了图片资源的泛型,是图片资源的包装类
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      //EngineResource的引用,直接回调SingleRequest的onResourceReady方法
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }

    //从LruCache缓存中获取资源
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      //从缓存中获取到资源,直接回调SingleRequest的onResourceReady方法
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }

    // Jobs 内部使用HashMap保存EngineKey到EngineJob的映射
    //EngineJob 负责管理下载,启动DecodeJob
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
      //保存cb和callbackExecutor,后面获取到资源后,回调cb的onResourceReady方法
      current.addCallback(cb, callbackExecutor);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }

    ///缓存中没有,则新建一个engineJob 
    EngineJob<R> engineJob =
        engineJobFactory.build(...);

    /* 
     * 新建一个DecodeJob
     * 负责从缓存或数据源中加载原始数据并通过解码器转换为相应的资源类型(Resource)。
     * DecodeJob 实现了 Runnable 接口,由 EngineJob 将其运行在指定线程池中
     */
    DecodeJob<R> decodeJob =
        decodeJobFactory.build(...);

    //记录key和engineJob的映射
    jobs.put(key, engineJob);
    
    engineJob.addCallback(cb, callbackExecutor);
    //启动decodeJob
    engineJob.start(decodeJob);

    ...
    return new LoadStatus(cb, engineJob);
  }


}
  1. 根据图片请求的相关参数构建EngineKey。
  2. 从缓存中获取EngineKey对应的EngineResource对象,如果EngineResource不为空,直接回调SingleRequest的onResouceReady接口,然后返回;
  3. 如果换成中没有EngineKey对应的EngineResource对象,那么查看缓存中是否存在EngineKey对应的EngineJob对象:
    (1) 如果有缓存中存在对应的EngineJob对象,说明对应的图片正在加载中,添加一个新的ResourceCallback和callbackExecutor到EngineJob中,最后直接返回一个新的LoadStatus。添加了回调接口后,图片资源下载成功后,可以回调本次添加ResourceCallback的onResourceReady方法。
    (2) 如果缓存中没有EngineJob,就新建一个EngineJob和DecodeJob,然后启动DecodeJob任务。

4、engineJob.start(decodeJob)

EngineJob负责管理图片请求回调,以及图片下载完成后执行回调。
DecodeJob负责从磁盘缓存或数据源中加载原始数据并通过解码器转换为相应的资源类型。

class EngineJob<R> implements DecodeJob.Callback<R>,
    Poolable {

  public synchronized void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;

    //如果是要解码磁盘的图片资源,返回true, GlideExecutor为diskCacheExecutor,否则调用getActiveSourceExecutor()
    //diskCacheExecutor为磁盘缓存加载线程池,不允许用于网络操作
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }

  //如果要解密磁盘缓存中的资源返回true, 否则返回false
  boolean willDecodeFromCache() {
    Stage firstStage = getNextStage(Stage.INITIALIZE);
    return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
  }

  //返回三种类型的线程池
  //sourceUnlimitedExecutor : 图片源网络加载线程池,没有核心线程数, 线程数无限制
  //animationExecutor : 动画加载线程池
  //sourceExecutor : 图片源网络加载线程池,有核心线程数,线程数有限
  private GlideExecutor getActiveSourceExecutor() {
    return useUnlimitedSourceGeneratorPool
        ? sourceUnlimitedExecutor : (useAnimationPool ? animationExecutor : sourceExecutor);
  }

}

  1. GlideExecutor可能为diskCacheExecutor、sourceUnlimitedExecutor 、animationExecutor 、sourceExecutor其中一种,把DecodeJob提交给线程池执行。
  2. DecodeJob实现了Runnable接口,EngineJob的start方法就是启动decodeJob的线程,执行decodeJob的run方法。
4.1 DecodeJob.run()
class DecodeJob<R> {

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

      if (isCancelled) {
        //如果取消加载,调用notifyFailed()通知加载资源失败
        notifyFailed();
        return;
      }
      runWrapped();

      ...
  }

  //decodeJob初始化时, runReason被设置为RunReason.INITIALIZE
  private void runWrapped() {
    switch (runReason) {
      case INITIALIZE:
        //判断要解码的数据来源,构建DataFetcherGenerator实例,执行runGenerators方法
        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);
    }
  }

  //getNextStage方法是要确定我们将要解码的数据是来源于哪里的数据
  //通常判断顺序为INITIALIZE -> RESOURCE_CACHE(图片转换之后的磁盘缓存) -> DATA_CACHE(原图的磁盘缓存) -> SOURCE(数据源)
  private Stage getNextStage(Stage current) {
    switch (current) {
      //INITIALIZE为Stage的初始状态
      case INITIALIZE:
        // 如果decodeCachedResource() 为 true, 表示尝试解码缓存中已经被转换的图片
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
      case RESOURCE_CACHE:
        // 如果decodeCachedData() 为 true,表示尝试解码磁盘中缓存的原始图片
        return diskCacheStrategy.decodeCachedData()
            ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
      case DATA_CACHE:
        // 如果调用者选择只用缓存中检索资源,则跳过从数据源加载
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
  }

  //根据Stage的枚举值来获取DataFetcherGenerator, 返回DataFetcherGenerator的子类
  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;
    //这里判断一下,之后主要是执行currentGenerator.startNext()方法执行后续的逻辑
    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();
    }

  }

}

Stage是DecodeJob的内部枚举类,用于表示所要解码数据的来源(内存缓存, 磁盘缓存),初始化状态是INITIALIZE。

  1. 这里首先是要调用getNextStage()方法确定需要解码的数据来源,是缓存的图片还是原始图片;
  2. 根据要解码的数据来源,构建对应的DataFetcherGenerator派生类(ResourceCacheGenerator, DataCacheGenerator等);DataFetcherGenerator负责构建DataFetcher实例, DataFetcher接口负责加载图片数据
  3. 启动DataFetcherGenerator,调用DataFetcherGenerator的startNext()方法,构建DataFetcher。
  4. 默认情况下,一开始会调用ResourceCacheGenerator的startNext()方法,获取磁盘缓存的数据。
  5. 如果磁盘没有缓存到对应的图片数据,要从数据源头加载图片时(比如从网络加载图片),会调用SourceGenerator的startNext()方法。

5、 SourceGenerator#startNext()

对应从数据源头加载数据的场景,负责构建DataFetchers。

class SourceGenerator implements DataFetcherGenerator,
    DataFetcher.DataCallback<Object>,
    DataFetcherGenerator.FetcherReadyCallback {

  private final DecodeHelper<?> helper;
  private volatile ModelLoader.LoadData<?> loadData;

  @Override
  public boolean startNext() {
    ...

    sourceCacheGenerator = null;

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

}
  • ModelLoader负责将多种复杂的数据模式转变成DataFetcher可以加载的的具体资源类型。
  • LoadData是ModelLoader的内部类,保存了图片对应的唯一Key,备用key集合缓存,以及对应DataFetcher派生类。
  • DataFetcher是真正负责加载资源的类,通过不同的派生类实现来加载不同的数据。

当我们加载网络图片源数据时,loadData.fetcher的实例是HttpUrlFetcher,即调用HttpUrlFetcher的loadData方法来加载网络图片源数据。

5.1 HttpUrlFetcher#loadData()
 @Override
  public void loadData(@NonNull Priority priority,
      @NonNull DataCallback<? super InputStream> callback) {

      ...
      //获取图片资源的输入流
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
       //回调数据
      callback.onDataReady(result);
      ...
  }

  //通过HttpURLConnection加载网络图片,返回图片输入流
  private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
      Map<String, String> headers) throws IOException {
    ...
    
    urlConnection = connectionFactory.build(url);
    ...
    urlConnection.connect();
    // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
    stream = urlConnection.getInputStream();
    if (isCancelled) {
      return null;
    }
    final int statusCode = urlConnection.getResponseCode();
    if (isHttpOk(statusCode)) {
      return getStreamForSuccessfulRequest(urlConnection);
    }
    ...
  }

HttpUrlFetcher加载网络图片数据就是通过HttpURLConnection连接url,获取图片输入流,然后通过回调接口把输入流返回出去。callback.onDataReady()首先会回调SourceGenerator类的onDataReady()方法。

6、SourceGenerator#onDataReady()

当数据获取成功后,需要执行的就是缓存图片和把图片设置到图片控件上了。

  //SourceGenerator#onDataReady()
  @Override
  public void onDataReady(Object data) {
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
    if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      dataToCache = data;//把inputStream赋值给dataToCache 
      //cb是SourceGenerator构造函数传递进来的,cb的实例是DecodeJob
      cb.reschedule();
    } 
    ...
  }

  //DecodeJob#reschedule
  @Override
  public void reschedule() {
    runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
    //callback是DecodeJob的init方法传递进来的,callback的实例是EngineJob
    callback.reschedule(this);
  }

  //EngineJob#reschedule()
  @Override
  public void reschedule(DecodeJob<?> job) {
    //再次把DecodeJob提交到线程池中执行,回调DecodeJob的run方法。
    getActiveSourceExecutor().execute(job);
  }

数据下载成功后,会经过很多的回调方法,回调过程为SourceGenerator#onDataReady() --> DecodeJob#reschedule() -> EngineJob#reschedule() --> DecodeJob#run()。

6.1 再次运行DecodeJob线程
  //DecodeJob#run
  @Override
  public void run() {
      ...
      runWrapped();
      ...
  }
  
  private void runWrapped() {
    switch (runReason) {
      ...
      case SWITCH_TO_SOURCE_SERVICE:
        //runGenerators会再次调用SourceGenerator的startNext方法
        runGenerators();
        break;
      ...
  }

  //SourceGenerator#startNext()
  @Override
  public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      //把数据缓存到磁盘中
      cacheData(data);
    }
    
     //执行了cacheData方法时,会把sourceCacheGenerator重新赋值为DataCacheGenerator。
    //执行DataCacheGenerator的startNext方法
    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
      return true;
    }
    ...
}

第二次运行DecodeJob线程,会再次调用SourceCacheGenerator的startNext方法,因为在数据下载成功的时候,把inputSteam赋值给了dataToCache,所以startNext方法首先调用cacheData()方法对数据进行磁盘缓存,然后调用DataCacheGenerator的startNext()方法。

6.2 DataCacheGenerator#startNext()
  @Override
  public boolean startNext() {
    ...
    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
      loadData =
          modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
              helper.getOptions());
      if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
        started = true;
        // 这里的 fetcher 为 ByteBufferFetcher,调用其 loadData() 的时候又会把自身传递过去
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

DataCacheGenerator类中, loadData.fetcher的实例是ByteBufferFetcher对象,loadData.fetcher.loadData就是调用ByteBufferFetcher的loadData方法,同时DataCacheGenerator把对象自身作为回调接口传递给ByteBufferFetcher。

    //ByteBufferFetcher#loadData()
    @Override
    public void loadData(@NonNull Priority priority,
        @NonNull DataCallback<? super ByteBuffer> callback) {
      ByteBuffer result;
      try {
        //读取缓存文件,获取图片文件的ByteBuffer数据
        result = ByteBufferUtil.fromFile(file);
      } catch (IOException e) {
        ...
        callback.onLoadFailed(e);
        return;
      }
      //回调到DataCacheGenerator的onDataReady方法
      callback.onDataReady(result);
    }

  //DataCacheGenerator#onDataReady()
  @Override
  public void onDataReady(Object data) {
    //cb对象是SourceGenerator,所以又回调到SourceGenerator的onDataFetcherReady方法
    cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
  }

    //SourceGenerator#onDataFetcherReady()
  @Override
  public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
      DataSource dataSource, Key attemptedKey) {
    //SourceGenerator的cb是DecodeJob对象,所以再回调到DecodeJob的onDataFetcherReady()方法
    cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
  }

ByteBufferFetcher的loadData方法就是读取图片的磁盘缓存转换成ByteBuffer数据,然后把数据回调给DecodeJob对象。

7、解析图片数据:DecodeJob#onDataFetcherReady()

  @Override
  public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
      DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;  //sourceKey是图片的网络url地址
    this.currentData = data;  //data是图片数据,
    this.currentFetcher = fetcher;  //ByteBufferFetcher
    this.currentDataSource = dataSource;  //图片的数据来源,为REMOTE,即远端图片数据源
    this.currentAttemptingKey = attemptedKey; //attemptedKey和sourceKey一样
    if (Thread.currentThread() != currentThread) {
      ...
    } else {
      try {
        // 调用 decodeFromRetrievedData 解析图片数据
        decodeFromRetrievedData();
      }
      ...
    }
  }

  //解析图片数据
  private void decodeFromRetrievedData() {
    
    Resource<R> resource = null;
    try {
      //currentFetcher为ByteBufferFetcher,
      //currentData为图片数据
      //currentDataSource为DATA_DISK_CACHE
      //解码图片数据,转换成Resource类型(LazyBitmapDrawableResource的实例)
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }

  //把图片资源回调出去,然后根据options参数,缓存转换的图片到磁盘中。
  private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
    if (resource instanceof Initializable) {
      //resource对象为LazyBitmapDrawableResource实例,是BitmapResource的包装类
      //initialize方法是执行BitmapResource的initialize方法,执行bitmap.prepareToDraw();
      ((Initializable) resource).initialize();
    }

    Resource<R> result = resource;
    LockedResource<R> lockedResource = null;
    if (deferredEncodeManager.hasResourceToEncode()) {
      lockedResource = LockedResource.obtain(resource);
      result = lockedResource;
    }

    notifyComplete(result, dataSource);

    stage = Stage.ENCODE;
    try {
      if (deferredEncodeManager.hasResourceToEncode()) {
        //根据options参数,缓存转换的图片到磁盘中
        deferredEncodeManager.encode(diskCacheProvider, options);
      }
    } finally {
      if (lockedResource != null) {
        lockedResource.unlock();
      }
    }

    //编码完成,释放资源
    onEncodeComplete();
  }

  //图片资源获取成功,回调出去
  private void notifyComplete(Resource<R> resource, DataSource dataSource) {
    setNotifiedOrThrow();
    //callback为EngineJob的实例对象,回调到EngineJob的onResourceReady方法
    callback.onResourceReady(resource, dataSource);
  }
  1. onDataFetcherReady首先就是把图片数据解析成Resource图片包装类。
  2. 把图片资源回调给EngineJob对象,然后根据options参数,缓存转换的图片到磁盘中。
7.1 EngineJob#onResourceReady()
//在执行engine.load方法中, 代码current.addCallback(cb, callbackExecutor)把SingleRequest设置给EngineJob对象
synchronized void addCallback(final ResourceCallback cb, Executor callbackExecutor) {
  cbs.add(cb, callbackExecutor);
}

  @Override
  public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    synchronized (this) {
      this.resource = resource;
      this.dataSource = dataSource;
    }
    notifyCallbacksOfResult();
  }

  
  void notifyCallbacksOfResult() {
    ResourceCallbacksAndExecutors copy;
    Key localKey;
    EngineResource<?> localResource;
    synchronized (this) {
      ...
      //把resource包装成EngineResource
      engineResource = engineResourceFactory.build(resource, isCacheable);
      hasResource = true;
      copy = cbs.copy();//ResourceCallbacksAndExecutors
      localKey = key;
      localResource = engineResource;
    }

    //listener为Engine实例对象,再回调到Engine的onEngineJobComplete方法
    listener.onEngineJobComplete(this, localKey, localResource);

    for (final ResourceCallbackAndExecutor entry : copy) {
      //把cb回调传递给CallResourceReady,并执行CallResourceReady线程任务。
      entry.executor.execute(new CallResourceReady(entry.cb));
    }

  }


private class CallResourceReady implements Runnable {
    private final ResourceCallback cb;
    CallResourceReady(ResourceCallback cb) {
      this.cb = cb;
    }
    @Override
    public void run() {
      synchronized (EngineJob.this) {
        if (cbs.contains(cb)) {
          ...
          callCallbackOnResourceReady(cb);
          ...
        }
      }
    }
  }

  
  synchronized void callCallbackOnResourceReady(ResourceCallback cb) {
    try {
      //cb为SingleRequest实例对象,回调到SingleRequest的onResourceReady方法中
      cb.onResourceReady(engineResource, dataSource);
    }
    ...
  }
  1. 先把Resource对象包装成EngineResource。
  2. listener.onEngineJobComplete()方法会回调到Engine#onEngineJobComplete()的方法,把EngineResource对象回调给Engine。
  3. entry.executor.execute(new CallResourceReady(entry.cb))启动CallResourceReady线程。cb是SingleRequest实例对象,回调到SingleRequest的onResourceReady方法中,并且把EngineResource资源对象传递给SingleRequest对象。
8、Engine#onEngineJobComplete()

对EngineResource执行缓存操作。

  @Override
  public synchronized void onEngineJobComplete(
      EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
    // A null resource indicates that the load failed, usually due to an exception.
    if (resource != null) {
      //Engine实现了ResourceListener的接口
      //记录key和ResourceListener接口的实现类(Engine类实例对象)到EngineResource对象中
      //当EngineResource的release方法被执行时,会回调ResourceListener的onResourceReleased方法,即回调到Engine类的onResourceReleased方法中
      resource.setResourceListener(key, this);
      
      //把数据缓存到activeResources中,Glide的第一级缓存,软引用缓存
      if (resource.isCacheable()) {
        activeResources.activate(key, resource);
      }
    }

    jobs.removeIfCurrent(key, engineJob);
  }

  //当EngineResource对象的release方法执行时,回调到此方法
  @Override
  public synchronized void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
    //从第一级缓存中去掉EngineResource对象
    activeResources.deactivate(cacheKey);
    if (resource.isCacheable()) {
      //把EngineResource对象保存到cache,Glide的第二级缓存,
      //cache对象是LruResourceCache实例对象, LruCache的子类
      cache.put(cacheKey, resource);
    } else {
      resourceRecycler.recycle(resource);
    }
  }
  • 先把EngineKey和Engine设置给EngineResource对象保存起来。当EngineResource对象被释放时,EngineResource的release方法会回调Engine的onResourceReleased方法,从一级缓存中删除EngineResource,然后保存到二级缓存中。
  • 然后把EngineResource保存到Glide的一级缓存activeResources中。
9、SingleRequest#onResourceReady()
 @Override
  public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
    ...
    Object received = resource.get();//从EngineResource中获取BitmapDrawable对象
    ...
    //调用onResourceReady重载方法
    onResourceReady((Resource<R>) resource, (R) received, dataSource);
  }


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

    ...
    status = Status.COMPLETE;//设置状态为完成状态
    ...
    isCallingCallbacks = true;
    try {
      boolean anyListenerHandledUpdatingTarget = false;
      ...
      if (!anyListenerHandledUpdatingTarget) {
        Transition<? super R> animation =
            animationFactory.build(dataSource, isFirstResource);
        //target为DrawableImageViewTarget, 
        //回调target的onResourceReady方法,最后会回调DrawableImageViewTarget的setResource方法
        target.onResourceReady(result, animation);
      }
    } finally {
      isCallingCallbacks = false;
    }

    notifyLoadSuccess();
  }

  //BitmapImageViewTarget#setResource
  @Override
  protected void setResource(Bitmap resource) {
    view.setImageBitmap(resource);//给控件设置bitmap图像
  }

SingleRequest的onResourceReady方法会回调用target的onResourceReady方法,由于target是DrawableImageViewTarget的实例,最终会回调到BitmapImageViewTarget的setResource方法,给view设置bitmap资源。

总结: into(imageView)的大体流程如下。
1、首先构建图片控件的包装类ViewTarget,实例为DrawableImageViewTarget或者BitmapImageViewTarget。
2、构建request,获取SingleRequest实例对象,并执行reqest.begin方法开始请求。
3、构建EngineJob和DecodeJob,通过EngineJob启动decodeJob的任务。
4、构建DataFetcher实例,通过HttpUrlConnection请求图片网络url,获取图片输入流,并把输入流回调出去。
5、缓存图片到磁盘中,继续回调图片流。
6、解析图片数据,转换成EngineResource图片包装类。
7、缓存图片到Glide的一级缓存中,并设置后EngineResource释放时,缓存图片到二级缓存中。
8、设置图片资源到图片控件中。

into.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容