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源碼。有興趣的同窗能夠關注下。

相關文章
相關標籤/搜索