Glide-源码分析(一)

前言

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

源码分析

今天只分析最简单的一行代码,后面会慢慢深刻。 虽然只有一行代码,可是里面的整个逻辑确实很是复杂。数组

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对象,以下bash

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对象里面存的东西不少,上面初始化了不少重要的东西,先不深刻去看,可是根据名字也能大概的猜到对象的做用。app

  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出来的RequestManagerRetrieveride

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源码。有兴趣的同窗能够关注下。

相关文章
相关标签/搜索