Glide-源码分析(一)

前言

前面几片文章主要介绍了下Picasso,相对来说Picasso源码看起来会比较轻松,所以如果想研究图片框架的话,建议先从Picasso下手,这样会比较容易。

源码分析

今天只分析最简单的一行代码,后面会慢慢深入。
虽然只有一行代码,但是里面的整个逻辑确实非常复杂。

Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(ivTest)

对,这应该也是我们使用Glide时候最常用的一句代码,下面我们就一步步跟入。

  1. with
//------Glide.java------

//with重载方法有很多,这里先讲一个
 public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }

private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    return Glide.get(context).getRequestManagerRetriever();
  }

第一次触发Glide.get方法,默认创建一个Glide对象,如下

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

    return glide;
  }

 private static void checkAndInitializeGlide(@NonNull Context context) {
    isInitializing = true;
    initializeGlide(context);
    isInitializing = false;
  }

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

//一步步往下看,就到了这里,真正开始创建Glide对象的方法
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
   ....
    //这里代码很多,都省略,直接看最关键的一个方法,build
    Glide glide = builder.build(applicationContext);
   ....
    Glide.glide = glide;
  }

以上是查找的过程的代码,不是特别重要,下面是GlideBuilder的build方法,非常重要。

Glide build(@NonNull Context context) {
    if (sourceExecutor == null) {
      sourceExecutor = GlideExecutor.newSourceExecutor();
    }

    if (diskCacheExecutor == null) {
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    }

    if (animationExecutor == null) {
      animationExecutor = GlideExecutor.newAnimationExecutor();
    }

    if (memorySizeCalculator == null) {
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    }

    if (connectivityMonitorFactory == null) {
      connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
    }

    if (bitmapPool == null) {
      int size = memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) {
        bitmapPool = new LruBitmapPool(size);
      } else {
        bitmapPool = new BitmapPoolAdapter();
      }
    }

    if (arrayPool == null) {
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }

    if (memoryCache == null) {
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }

    if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }

    if (engine == null) {
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(),
              GlideExecutor.newAnimationExecutor(),
              isActiveResourceRetentionAllowed);
    }

    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock(),
        defaultTransitionOptions);
  }

Glide对象里面存的东西很多,上面初始化了很多重要的东西,先不深入去看,但是根据名字也能大概的猜到对象的作用。

  1. sourceExecutor 获取源数据线程池
  2. diskCacheExecutor 获取diskcache线程池
  3. animationExecutor 应该是跟动画有关的线程池
  4. memorySizeCalculator 应该是个工具类,来计算内存的大小
  5. connectivityMonitorFactory 应该是连接监听的一个工厂类
  6. bitmapPool 存放bitmap的池
  7. arrayPool 存放数组的池
  8. memoryCache 资源缓存对象
  9. diskCacheFactory disk cache工厂类
  10. requestManagerRetriever requestManager训练器

大概就这样一个初步的印象,可能不正确,后面可以慢慢验证。
下面继续回到刚才的with的方法。

 @NonNull
  private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    return Glide.get(context).getRequestManagerRetriever();
  }

这里的getRequestManagerRetriever,其实就是build方法中直接new出来的RequestManagerRetriever

public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }

所以我们再跟进去看下RequestManagerRetrieverget方法

 @NonNull
  public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }
...
  @NonNull
  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    //创建一个SupportRequestManagerFragment,来获取生命周期的状态,来对图片进行管理(这个后面再深入,这里可以简单理解为,就是为了利用Fragment的生命周期)
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    //刚开始创建的SupportRequestManagerFragment的requestManager==null
    if (requestManager == null) {
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

get方法有很多重载,这里我们就以参数为FragmentActivity为例子。
get方法主要是为了创建RequestManager.

回过头再看Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(ivTest),
接下来就是调用了RequestManager对象的load方法

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

//调用了as方法,其实主要就是创建一个RequestBuilder对象,然后传入最终要转换成的资源类型,显然默认是转换为Drawable.class
 @NonNull
  @CheckResult
  public <ResourceType> RequestBuilder<ResourceType> as(
      @NonNull Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
  }
...

 @NonNull
  @Override
  @CheckResult
  public RequestBuilder<TranscodeType> load(@Nullable String string) {
    return loadGeneric(string);
  }
...

//调用load方法传入url地址时,并没有真正的去发生请求获取到图片,只是设置了一个参数
@NonNull
  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }

这里的代码其实比较简单,没有什么好介绍的,简单的说就是使用了建造者模式,然后创建了一个新的对象RequestBuilder,然后传入一些参数。既然是建造者模式,那么最后RequestBuilder肯定会生成一个Request

接下来再回头看

Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(ivTest)

下面就应该是调用RequestBuilderinto方法了

@NonNull
  public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
  ...
    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions);
  }
...
private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @NonNull RequestOptions options) {
     ...
    Request request = buildRequest(target, targetListener, options);

    //获取到当前target绑定的request请求,如果现在正在运行的这个请求跟这个target之前绑定的请求是一样的话,
   //就判断下之前的请求是否有再运行,没有运行就开始运行,有运行就不操作。并且回收当前要运行的Request对象
    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跟request绑定
    target.setRequest(request);
    //这里才是正在发起请求的地方
    requestManager.track(target, request);
    return target;
  }

into方法中有2句比较关键的地方,这里提取出来单独来讲。

1. Request request = buildRequest(target, targetListener, options);
2. requestManager.track(target, request);

先看1,在RequestBuilder中调用buildRequest,构建一个Request对象

private Request buildRequest(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      RequestOptions requestOptions) {
    return buildRequestRecursive(
        target,
        targetListener,
        /*parentCoordinator=*/ null,
        transitionOptions,
        requestOptions.getPriority(),
        requestOptions.getOverrideWidth(),
        requestOptions.getOverrideHeight(),
        requestOptions);
...
private Request buildRequestRecursive(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      RequestOptions requestOptions) {

  ...
    Request mainRequest =
        buildThumbnailRequestRecursive(
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions);

   ...
    return errorRequestCoordinator;
  }
...

//顾名思义,创建一个缩略图的Request,先判断是否有设置缩放的一些熟悉
//如果没有,就获取一个没有缩放的Request
private Request buildThumbnailRequestRecursive(
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      RequestOptions requestOptions) {
    if (thumbnailBuilder != null) {
     ...
    } else if (thumbSizeMultiplier != null) {
     ...
      Request thumbnailRequest =
          obtainRequest(
              target,
              targetListener,
              thumbnailOptions,
              coordinator,
              transitionOptions,
              getThumbnailPriority(priority),
              overrideWidth,
              overrideHeight);

      coordinator.setRequests(fullRequest, thumbnailRequest);
      return coordinator;
    } else {
    
      return obtainRequest(
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight);
    }
  }

//绕了半天,这里才是真正创建一个Request的地方
private Request obtainRequest(
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      RequestOptions requestOptions,
      RequestCoordinator requestCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight) {
    return SingleRequest.obtain(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory());
  }

看一些优秀的三方源码,总是这样,方法重载很多,方法参数很多,很容易晕,大家要一步步往里面跟,总能看懂的。

这里我们最后找到的是创建了一个SingleRequest对象。当然如果说你在
Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(ivTest)设置了一些宽高,或者是缩放的属性,那么走的分支可能就不是这个。后面我们再分析。先从最简单的分支入手,一步步解析。

接下来我们继续看第2句关键的代码

requestManager.track(target, request);
void track(@NonNull Target<?> target, @NonNull Request request) {
    ...
    requestTracker.runRequest(request);
  }
 public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      //正常情况isPaused=false,走这个分支,开始请求
      request.begin();
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }
...

public void begin() {
   ...
    status = Status.WAITING_FOR_SIZE;
    //这里先判断overrideWidth,overrideHeight是否合法
    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());
    }
   ...
  }

我们这里直接看到begin方法

 private static boolean isValidDimension(int dimen) {
    return dimen > 0 || dimen == Target.SIZE_ORIGINAL;
  }

由于我们并没有设置宽高,所以返回false,走下面分支

 target.getSize(this);

public void getSize(@NonNull SizeReadyCallback cb) {
    sizeDeterminer.getSize(cb);
  }


void getSize(@NonNull SizeReadyCallback cb) {
      int currentWidth = getTargetWidth();
      int currentHeight = getTargetHeight();
      if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
        cb.onSizeReady(currentWidth, currentHeight);
        return;
      }

      if (!cbs.contains(cb)) {
        cbs.add(cb);
      }
      if (layoutListener == null) {
        ViewTreeObserver observer = view.getViewTreeObserver();
        layoutListener = new SizeDeterminerLayoutListener(this);
        observer.addOnPreDrawListener(layoutListener);
      }
    }

这里比较关键的就是target.getSize(this);方法中的参数this,这里的this是一个SizeReadyCallback .
SingleRequest实现了SizeReadyCallback

这里就是等待layout布局后,ImageView有了widthheight后就会进入SingleRequestonSizeReady回调方法。

主要的通过

  ViewTreeObserver observer = view.getViewTreeObserver();
  layoutListener = new SizeDeterminerLayoutListener(this);
  observer.addOnPreDrawListener(layoutListener);

这3句来监听ImageView的布局之后的一个回调,也就是有了widthheight之后的回调。

如果我们本身设置了缩放,或者是宽高属性,那么Glide就会直接使用widthheight当作参数,调用
onSizeReady.下面我们直接看。

public void onSizeReady(int width, int height) {
   ...
    if (status != Status.WAITING_FOR_SIZE) {
      return;
    }
    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);
    ...
    if (status != Status.RUNNING) {
      loadStatus = null;
    }
    ...
  }

这里比较关键的地方

  1. 状态的切换
  2. 调用engine.load

第1点就不说了,直接看上面代码就好。
直接看第2点engine.load
我们首先看下engine这个对象是在哪里初始化的。

  private Request obtainRequest(
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      RequestOptions requestOptions,
      RequestCoordinator requestCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight) {
    return SingleRequest.obtain(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory());
  }

可以看出来是前面构建SingleRequest对象的时候glideContext.getEngine()传入的一个参数。

glideContext =
        new GlideContext(
            context,
            arrayPool,
            registry,
            imageViewTargetFactory,
            defaultRequestOptions,
            defaultTransitionOptions,
            engine,
            logLevel);

而glideContext中的engine也是参数传入的。
最终找到

@NonNull
  Glide build(@NonNull Context context) {
   ...

    if (engine == null) {
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(),
              GlideExecutor.newAnimationExecutor(),
              isActiveResourceRetentionAllowed);
    }

...

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock(),
        defaultTransitionOptions);
  }

是在创建Glide的时候new出来的一个Engine,不自己传入的话,会默认构建一个。然后供后面使用。
下面我们继续看Engine.load方法

public <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) {
    ...
    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);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }

    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);

    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);
    engineJob.start(decodeJob);

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

代码很多,我们就看重点几个地方。
先通过参数,生成key,通过key,去获取缓存数据,如果有缓存就直接调用SingleRequestonResourceReady方法。

//生成key,其实可以理解为就是一个字符串,然后key-value,获取到对应的缓存
 EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);
//然后调用
loadFromActiveResources
//然后调用
loadFromCache

如果缓存中都没有数据,那么就继续下面

 EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
      current.addCallback(cb);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }

先从jobs里面通过key获取前面已经加入的EngineJob。如果有,就直接current.addCallback(cb);
意思就是说,前面如果已经执行过一个任务了,就会把任务添加到jobs,如果后面遇到相同的任务了,就直接在jobs里面获取,可以把jobs就认为是一个HashMap,根据key来保存。

如果说,是第一次运行任务,也就是加载图片,那么current==null,继续往下走。

EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);

    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);
    engineJob.start(decodeJob);
    ...
    return new LoadStatus(cb, engineJob);

创建2个对象,EngineJob和DecodeJob。
jobs.put(key, engineJob);这里是为了后面如果是加载相同的图片的话,这里会直接获取到EngineJob然后去处理,而不是每次都新建一个。

接下来继续engineJob.start(decodeJob);

public void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }
...
boolean willDecodeFromCache() {
    Stage firstStage = getNextStage(Stage.INITIALIZE);
    return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
  }

这里判断了下是使用diskCacheExecutor还是getActiveSourceExecutor(), 其实第一次看源码的时候,我们可以先来走一遍完整的流程,这2者具体的区别我们先不要太在意。

这2者其实都是一个ExecutorService,是用来处理线程的。

那我们继续。

class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
    Runnable,
    Comparable<DecodeJob<?>>,
    Poolable

DecodeJob实现了Runnable接口
这里调用

  executor.execute(decodeJob);

其实就是在线程池中找一个线程来执行decodeJob中的run方法。

@Override
  public void run() {

   ...
    DataFetcher<?> localFetcher = currentFetcher;
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      runWrapped();
    } catch (Throwable t) {
        ...
     }
}

//通过状态来获取不同的生成器,来生成资源
private void runWrapped() {
    switch (runReason) {
      case INITIALIZE:
        stage = getNextStage(Stage.INITIALIZE);
        currentGenerator = getNextGenerator();
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }
...
//获取当前状态的下一个状态
private Stage getNextStage(Stage current) {
    switch (current) {
      case INITIALIZE:
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
      case RESOURCE_CACHE:
        return diskCacheStrategy.decodeCachedData()
            ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
      case DATA_CACHE:
        // Skip loading from source if the user opted to only retrieve the resource from cache.
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
  }

上面最重要的方法就是runWrappeed
主要3点。

  1. 获取当前状态的下一个状态,然后赋值给当前状态
  2. 获取与当前匹配的Generator
  3. 运行生成器来获取资源。

我们先来看第一点,也就是getNextStage方法,通过当前状态,来获取后面的一个状态。其实很简单。
状态的顺序就是

INITIALIZE(初始化)-> RESOURCE_CACHE(获取内存缓存)-> DATA_CACHE(获取磁盘缓存)-> SOURCE(真正去请求资源)-> FINISHED(完成)

正常情况下,就会按这样步骤一个个来,但是有些时候我们会设置不缓存的一些参数,那么就会跳过某个步骤。

在代码中也有体现

 case INITIALIZE:
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);

初始化后应该是从获取资源缓存,但是diskCacheStrategy.decodeCachedResource()返回false的话,那么就直接获取getNextStage(Stage.RESOURCE_CACHE),也就是资源缓存的下一个状态。

DiskCacheStrategy代表缓存的策略,一共有

  1. DiskCacheStrategy.ALL
  2. DiskCacheStrategy.NONE
  3. DiskCacheStrategy.DATA
  4. DiskCacheStrategy.RESOURCE
  5. DiskCacheStrategy.AUTOMATIC

我们这里来看下DiskCacheStrategy.NONE

 public static final DiskCacheStrategy NONE = new DiskCacheStrategy() {
        public boolean isDataCacheable(DataSource dataSource) {
            return false;
        }

        public boolean isResourceCacheable(boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
            return false;
        }
        public boolean decodeCachedResource() {
            return false;
        }
        public boolean decodeCachedData() {
            return false;
        }
    };

这里就都返回false。不允许获取缓存数据。

下面来看第2点,获取Generator

 private DataFetcherGenerator getNextGenerator() {
    switch (stage) {
      case RESOURCE_CACHE:
        return new ResourceCacheGenerator(decodeHelper, this);
      case DATA_CACHE:
        return new DataCacheGenerator(decodeHelper, this);
      case SOURCE:
        return new SourceGenerator(decodeHelper, this);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized stage: " + stage);
    }
  }

通过不同的stage获取到不同的Generator。一开始获取到ResourceCacheGenerator

下面看第3点,runGenerators

private void runGenerators() {
    ...
    while (!isCancelled && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();
      if (stage == Stage.SOURCE) {
        reschedule();
        return;
      }
    }
  }

这里代码很简单,取消的情况先不考虑,主要是这句代码

!(isStarted = currentGenerator.startNext())

Generator中注册了很多ModelLoader<File, ?>ModelLoader<File, ?>可以生成对应的处理资源的LoadData,
不同的LoadData只能加载自己能加载到的资源。

public boolean startNext() {
   ...
    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;
  }

最终调用的是LoadDatafetcher的loadData方法。
这里的fetcherHttpUrlFetcher(为什么是这个后面可以再深入讲,先走完整个流程)。

 public void loadData(@NonNull Priority priority,
      @NonNull DataCallback<? super InputStream> callback) {
    ...
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
      callback.onDataReady(result);
  ...
  }

loadDataWithRedirects这个方法就不深入介绍了,使用了HttpURLConnection去请求资源。
请求完成后,调用了onDataReady方法,把结果往上传。

这里我们就要一步步往上找到回调方法。

首先刚才在SourceGenerator调用的

loadData.fetcher.loadData(helper.getPriority(), this);

会发现,参数 DataCallback就是SourceGenerator

所以回调的其实是SourceGeneratoronDataReady方法

 @Override
  public void onDataReady(Object data) {
  ...
      dataToCache = data;
      cb.reschedule();
   ...
  }

这里又有一个cb也就是Callback,继续往前找,发现是DecodeJob,
所以这里又调用了,DecodeJob.reschedule();

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

DecodeJob中又调用了callback.reschedule,其实这里的callbackEngineJob。很多优秀的三方库就是这样,绕来绕去的,看起来比较费劲。

 @Override
  public void reschedule(DecodeJob<?> job) {
    getActiveSourceExecutor().execute(job);
  }

这里会发现一个很奇怪的东西,因为在前面我们已经介绍过了,入口就是执行DecodeJobrun方法,然后执行完成之后一步步回调,这里竟然又去执行DecodeJobrun,死循环么,当然不是,我们继续往下看。

之后的流程跟前面都一样,这里就不再赘述了,然后又到了SourceGeneratorstartNext方法

public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }

    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
      return true;
    }
   ..
    return started;
  }
...
private void cacheData(Object dataToCache) {
  ...
    sourceCacheGenerator =
        new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
  }

这个时候跟之前就不一样了,因为数据请求已经回来了,dataToCache!=null,然后调用cacheData方法,把数据缓存起来。
调用cacheData方法之后,最后创建了一个DataCacheGenerator。然后调用startNext方法。

public boolean startNext() {
    while (modelLoaders == null || !hasNextModelLoader()) {
      sourceIdIndex++;
      if (sourceIdIndex >= cacheKeys.size()) {
        return false;
      }

      Key sourceId = cacheKeys.get(sourceIdIndex);
      @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
      Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
      cacheFile = helper.getDiskCache().get(originalKey);
      if (cacheFile != null) {
        this.sourceKey = sourceId;
        modelLoaders = helper.getModelLoaders(cacheFile);
        modelLoaderIndex = 0;
      }
    }

    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;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

这里的代码呢,其实跟前面的SourceGenrator差不多,由于前面已经缓存了数据,所以cacheFile!=null,获取到的modelLoader其实是ByteBufferFileLoader,然后fetcherByteBufferFetcher,所以

  public void loadData(@NonNull Priority priority,
        @NonNull DataCallback<? super ByteBuffer> callback) {
      ByteBuffer result;
      try {
        result = ByteBufferUtil.fromFile(file);
      } catch (IOException e) {
        ...
        callback.onLoadFailed(e);
        return;
      }

      callback.onDataReady(result);
    }

直接加载文件,返回二进制数组,然后调用回调函数。这里的callback其实就是DataCacheGenerator,跟前面一样的,就是不停往前面找。仔细点,还是很简单的。

 @Override
  public void onDataReady(Object data) {
    cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
  }

这里cb是DecodeJob

public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
      DataSource dataSource, Key attemptedKey) {
  ...
      runReason = RunReason.DECODE_DATA;
      callback.reschedule(this);
  ...

又开始了,设置了一下值runReason = RunReason.DECODE_DATA,又调用了callback也就是EngineJobreschedule方法。

这里我就不继续往前找了,最后还是调用了DecodeJobrun方法

public void run() {
   ...
      runWrapped();
   ...
  }
private void runWrapped() {
    switch (runReason) {
      ...
      case DECODE_DATA:
        decodeFromRetrievedData();
        break;
     ...
    }
  }
private void decodeFromRetrievedData() {
  ...
    Resource<R> resource = null;
    try {
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
   ...
    if (resource != null) {
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }

private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
 ....
    notifyComplete(result, dataSource);
...
  }

 private void notifyComplete(Resource<R> resource, DataSource dataSource) {
   ...
    callback.onResourceReady(resource, dataSource);
  }

这里就比较简单了,获取到资源然后解码后,调用callback也就是EngineJobonResourceReady方法

public void onResourceReady(Resource<R> resource, DataSource dataSource) {
   ...
   MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
 }

public boolean handleMessage(Message message) {
     ...
     switch (message.what) {
       case MSG_COMPLETE:
         job.handleResultOnMainThread();
        ...
   }

void handleResultOnMainThread() {
   ...
       cb.onResourceReady(engineResource, dataSource);
   ...
 }

这里的cb其实就是SingleRequest了。

public void onResourceReady(Resource<?> resource, DataSource dataSource) {
    ...
    onResourceReady((Resource<R>) resource, (R) received, dataSource);
  }

private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
    ...
  target.onResourceReady(result, animation);
   ...
  }

这里的target其实就是ImageViewTarget

  public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
   ...
      setResourceInternal(resource);
   ...
  }
private void setResourceInternal(@Nullable Z resource) {
  ...
    setResource(resource);
   ...
  }

 protected abstract void setResource(@Nullable Z resource);

可以看出setResource是一个抽象方法。
由于之前传入的是Drawable.class
所以这里的实现是DrawableImageViewTarget

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

这里的view其实就是我们的ImageView

到这里,最简单的Glide加载网络图片的流程已经走完。

如果对整个流程不懂的同学,其实是可以debug一下,然后一步一步跟进去。但是由于流程跳来跳去的,可能断点不是很好打。
大家可以先看下我的整个流程,了解大概之后就可以自己打断点了。

后续还会继续深入Glide源码。有兴趣的同学可以关注下。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容