Glide學習(一)—工作流程分析

前言

目前在Android中有許多圖片加載框架,比如UniversalImageLoader、Volley、Picasso、Fresco、Glide等。Glide作爲一個快速高效的Android圖片加載庫,是Android開發使用最多的圖片加載庫之一。因爲Glide的高性能、可擴展的特性,也是被Google推薦使用的圖片加載庫。

用過Glide的同學都知道,Glide僅僅使用一行代碼就可以將圖片加載到對應的位置。比如:Glide.with(activity).load(url).into(imageView); 可以將對應url的網絡圖片加載到一個ImageView中。

本篇文章不講Glide的使用。主要分析下Glide的加載流程用來深入的學習Glide。

以下基於Glide 4.8.0的源碼進分析

Glide的加載流程

在上面從url中加載圖片的例子中可以看到,Glide通過調用幾個簡單的方法就能實現圖片的加載。

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

雖然只是簡單的一行代碼,但是可以想到的是Glide做了大量的工作才能完成圖片的加載。在上面的代碼總共調用了三個方法,分別是with()、load()以及into()。接下來逐一分析。

從with()開始

public class Glide {
  @NonNull
  public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }

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

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

  @NonNull
  public static RequestManager with(@NonNull Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }

  @NonNull
  public static RequestManager with(@NonNull View view) {
    return getRetriever(view.getContext()).get(view);
  }
}

可以看到,在Glide中有許多with()方法的重載。其中傳入with()的參數可以是Activity、Fragment或者Context。每個with()方法都返回了一個RequestManager對象。接着往下看,通過getRetriever().get()方法得到RequestManager對象。

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

@NonNull
  public RequestManagerRetriever getRequestManagerRetriever() {
    return requestManagerRetriever;
  }

可以看出,RequestManager對象來自於RequestManagerRetriever的get方法。

@NonNull
  public RequestManager get(@NonNull Context context) {
    if (context == null) {
      throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {
      if (context instanceof FragmentActivity) {
        return get((FragmentActivity) context);
      } else if (context instanceof Activity) {
        return get((Activity) context);
      } else if (context instanceof ContextWrapper) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }

    return getApplicationManager(context);
  }

  @NonNull
  public RequestManager get(@NonNull FragmentActivity activity) {
    //.....省略代碼
    return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
  }

  @NonNull
  public RequestManager get(@NonNull Fragment fragment) {
    //.....省略代碼
    return supportFragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible());
  }

  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull Activity activity) {
      //.....省略代碼
      return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull View view) {
    //.....省略代碼
    return get(fragment);
  }

RequestManagerRetriever中get()方法也有很多種重載,分別處理不同的情況Context的情況、Activity、Fragment的情況。總共存在這兩種處理方案:這兩種方案的主要區別就是Glide的請求的生命週期的差異。

  • 處理參數爲Context的情況:在這種情況下最終會通過Application以及ApplicationLifecycle來構造RequestManager。這樣Glide的請求就是Application的生命週期。

  • 處理Activity、Fragment的情況:這種情況是通過創建一個不可見的Fragment加入到對應的Activity中來實現Glide的請求的生命週期。

以上是兩種不同的處理方式,關於Application的情況,Glide的生命週期是應用的生命週期,當應用被關閉是Glide會停止還沒有加載完的請求;關於Activity以及Fragment的情況,通過創建一個不可見的Fragment加入到對應的Activity中實現Glide的生命週期。當Glide在摸個Activity中加載圖片時,Activity退出時,Glide也會停止加載。

以下通過代碼看下這兩種情況:

//處理Application的情況
private RequestManager getApplicationManager(@NonNull Context context) {
    // Either an application context or we're on a background thread.
    if (applicationManager == null) {
      synchronized (this) {
        if (applicationManager == null) {
          Glide glide = Glide.get(context.getApplicationContext());
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(), //Application的生命週期回調接口
                  new EmptyRequestManagerTreeNode(),
                  context.getApplicationContext());
        }
      }
    }

    return applicationManager;
  }
//處理Activity的情況

//1.獲取不可見的Fragment
private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) { //parent可見,執行生命週期回調
          current.getGlideLifecycle().onStart();
        }
        pendingRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); //添加Fragment
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

private RequestManager fragmentGet(
      @NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);  //創建RequestManager對象
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

以上就是with()的調用情況,在with()方法中主要構造了RequestManager對象,並且會根據參數的不同來決定不同生命週期額加載邏輯。接下來要處理load()方法。我們可以知道load()方法是RequestManager中的方法,接下來分析load()方法。

load()方法

可以知道,load()方法是在RequestManager中的。

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

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

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

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

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

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

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

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

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

從代碼中可以看出load()方法也有很多重載的方法,這些方法對應了Glide加載圖片的不同類型Url、資源id、文件等。load()最終返回了RequestBuilder對象。

除此之外,還能看到一個asDrawable()方法,這個方法的意義是Glide最終以Drawable的形式加載圖片。除了asDrawable()方法外還有asBitmap()、asGif()等方法。我們從asDrawable()開始分析。

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

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

可以看到asDrawable()方法返回了一個RequestBuilder對象。RequestBuilder是泛型類,傳入的類型就是Glide最終加載圖片的類型。asDrawable()方法返回RequestBuilder對象,那麼接下來的load()方法就是RequestBuilder中的方法。

public RequestBuilder<TranscodeType> load(@Nullable Object model) {
    return loadGeneric(model);
  }

public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
    return loadGeneric(bitmap).apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
  }

  public RequestBuilder<TranscodeType> load(@Nullable Drawable drawable) {
    return loadGeneric(drawable).apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
  }

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

  public RequestBuilder<TranscodeType> load(@Nullable Uri uri) {
    return loadGeneric(uri);
  }

  public RequestBuilder<TranscodeType> load(@Nullable File file) {
    return loadGeneric(file);
  }

  public RequestBuilder<TranscodeType> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
    return loadGeneric(resourceId).apply(signatureOf(ApplicationVersionSignature.obtain(context)));
  }

  public RequestBuilder<TranscodeType> load(@Nullable URL url) {
    return loadGeneric(url);
  }

  public RequestBuilder<TranscodeType> load(@Nullable byte[] model) {
    RequestBuilder<TranscodeType> result = loadGeneric(model);
    if (!result.isDiskCacheStrategySet()) {
      result = result.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
    }
    if (!result.isSkipMemoryCacheSet()) {
      result = result.apply(skipMemoryCacheOf(true /*skipMemoryCache*/));
    }
    return result;
  }

可以看到,RequestBuilder中也有多種load()的重載方法,這些方法最終也都返回RequestBuilder對象。同時他們都會調用loadGeneric()方法。

private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }

loadGeneric()方法記錄了加載類型model。

以上就是load()方法的加載過程,邏輯並不複雜,在load()主要的工作就是構造RequestBuilder對象。

into()方法

在完成with()、load()方法後就只剩下最後一步了,into()方法最終會將獲取的圖片加載到ImageView中去。以上兩個方法中,我們看到只是構造了RequestManager以及RequestBuilder對象,並沒有做太多的工作,甚至連圖片的加載過程還沒開始。那個可以知道,在into()方法中將完成接下來的所有工作。

我們從代碼看起:

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    BaseRequestOptions<?> requestOptions = this;
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions = requestOptions.clone().optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions = requestOptions.clone().optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.
      }
    }

    return into(
        glideContext.buildImageViewTarget(view, transcodeClass), //這裏創建Target對象
        /*targetListener=*/ null,
        requestOptions,
        Executors.mainThreadExecutor());
  }

在上面的方法中,要將獲取的圖片加載到ImageView中。在方法的開始,處理了ImageView的縮放方式,然後保存在了RequestOptions中。接下來調用了其他重載的into()方法,在開始這個into()方法時,還創建了Target對象,這裏是DrawableImageViewTarget。Target對象的主要作用是保存目標View、request等信息。

private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> options,
      Executor callbackExecutor) {
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }
    //創建 Request -> 圖片加載請求
    Request request = buildRequest(target, targetListener, options, callbackExecutor);
    Request previous = target.getRequest(); //是否與前一個請求相同
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      request.recycle();
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        previous.begin();
      }
      return target;
    }

    requestManager.clear(target);
    target.setRequest(request); 
    requestManager.track(target, request); //發起請求

    return target;
  }

這個方法中主要構造了圖片獲取請求以及發起圖片請求。通過buildRequest()方法獲取了圖片請求,在構造Request的過程中,傳遞了很多參數,比如placeholderId、errorPlaceholder、diskCacheStrategy等,這裏不展開描述了。在構造完Request時,就開始發起請求。通過RequestManager的track()方法實現。

/**RequestManager**/
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request); //開始圖片請求
  }

/**RequestTracker**/
public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin(); //如果不是停止狀態,則開始請請求
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }

最終,在RequestTracker中開始請求。

public synchronized void begin() {
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();
    if (model == null) {
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        width = overrideWidth;
        height = overrideHeight;
      }
      int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
      //圖片加載失敗
      onLoadFailed(new GlideException("Received null model"), logLevel);
      return;
    }

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

    if (status == Status.COMPLETE) {
      //請求完成,加載圖片到對應的View
      onResourceReady(resource, DataSource.MEMORY_CACHE);
      return;
    }

    // Restarts for requests that are neither complete nor running can be treated as new requests
    // and can run again from the beginning.
    status = Status.WAITING_FOR_SIZE; //從這裏開始請求
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      //如果在構造請求時傳入了長和寬的參數
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      //獲取長和寬
      target.getSize(this);
    }

    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
      //這裏是加載佔位符圖片
      target.onLoadStarted(getPlaceholderDrawable());
    }
  }

在begin()方法中已經開啓了圖片加載流程,根據不同的運行狀態加載圖片。在開始status是WAITING_FOR_SIZE用來確定圖片尺寸。如果在構造請求時傳入了長和寬的參數直接開始下一步,否則調用Target對象的getSize()方法。繼續跟getSize()代碼的話,最終調用的還是onSizeReady()方法,這裏我們只分析onSizeReady()的方法。

public synchronized void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    if (status != Status.WAITING_FOR_SIZE) {
      return;
    }
    status = Status.RUNNING; //設置status爲RUNNING,接下來會執行佔位符的加載

    float sizeMultiplier = requestOptions.getSizeMultiplier();
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
    //這裏開始加載圖片,通過Engine
    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,
            callbackExecutor);
    if (status != Status.RUNNING) {
      loadStatus = null;
    }
    if (IS_VERBOSE_LOGGABLE) {
      logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
  }

可以看到在onSizeReady()方法中調用了Engine的load()方法。從這裏就開始了圖片的真正加載流程。接下來看看Engine的load()方法做了什麼。

public <R> LoadStatus load(
     /**省略參數顯示**/) {
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

    EngineKey key =
        keyFactory.buildKey(
            model,
            signature,
            width,
            height,
            transformations,
            resourceClass,
            transcodeClass,
            options);

    EngineResource<?> memoryResource;
    synchronized (this) {
      //先從緩存中獲取
      memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);

      if (memoryResource == null) {
        //獲取圖片
        return waitForExistingOrStartNewJob(
            glideContext,
            model,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            options,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache,
            cb,
            callbackExecutor,
            key,
            startTime);
      }
    }
    //圖片獲取完成,開始加載
    cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
    return null;
  }

在load()方法中先從緩存中獲取圖片數據,如果沒有在繼續獲取圖片。這裏不深入分析Glide的緩存原理。繼續下一步分析圖片的加載過程。

private <R> LoadStatus waitForExistingOrStartNewJob(
      /**省略參數**/) {
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
      current.addCallback(cb, callbackExecutor);
      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, callbackExecutor);
    engineJob.start(decodeJob); //開始加載
    return new LoadStatus(cb, engineJob);
  }

在waitForExistingOrStartNewJob()方法中創建了EngineJob和DecodeJob,然後通過EngineJob執行DecodeJob。

public synchronized void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor =
        decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor(); //通過不同的策略獲取不同線程池
    executor.execute(decodeJob);
  }

在EngineJob中通過使用Glide中的線程池開始執行DecodeJob任務。接下來分析DecodeJob中都做了些什麼。

class DecodeJob {
  @Override
  public void run() {
    //DecodeJob實現了Runnable接口
    GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
    DataFetcher<?> localFetcher = currentFetcher;
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      runWrapped(); //加載
    } catch (CallbackException e) {
      throw e;
    } catch (Throwable t) {
      if (stage != Stage.ENCODE) {
        throwables.add(t);
        notifyFailed(); //通知加載失敗
      }
      if (!isCancelled) {
        throw t;
      }
      throw t;
    } finally {
      if (localFetcher != null) {
        localFetcher.cleanup();
      }
      GlideTrace.endSection();
    }
  }
  //繼續執行加載過程
  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);
    }
  }
    
    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);
    }
  }
}

可以看到,在DecodeJob中正常加載的情況下,會調用runWrapped()方法。在這個方法中,主要的工作是根據不同的加載階段執行相應的加載過程。從getNextStage()方法的調用可以知道,如果不是從內存中取得話,最終會返回Stage.SOURCE,後獲取SourceGenerator。

在創建SourceGenerator時,有個變量decodeHelper,這個變量在初始化(執行init()方法)時會根據model創建DataFetcher對象。這裏我們的例子中使用的是url,所以會創建HttpUrlFetcher。在說明了接下來加載過程需要用到的角色後,我們繼續分析。

在獲取完SourceGenerator後,執行了runGenerators()方法。

private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    while (!isCancelled
        && currentGenerator != null
           //currentGenerator.startNext()這裏執行加載過程
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

      if (stage == Stage.SOURCE) {
        reschedule(); //重新執行
        return;
      }
    }
    // We've run out of stages and generators, give up.
    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
      notifyFailed();
    }
  }

/**SourceGenerator**/
public boolean startNext() {
    if (dataToCache != null) {
      //緩存數據
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }
    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
      return true;
    }
    sourceCacheGenerator = null;

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

在runGenerators()方法中調用SourceGenerator的startNext()方法。從代碼中可以看出,startNext()方法通過loadData.fetcher.loadData()方法繼續加載數據。在上面我們講到fetcher對象通過model選擇。這裏fetcher是HttpUrlFetcher。接下來看下HttpUrlFetcher的loadData()方法做了哪些事情。

public void loadData(
      @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    try {
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
      callback.onDataReady(result); //數據加載完成
    } catch (IOException e) {
      callback.onLoadFailed(e); //加載失敗回調
    }
  }

  private InputStream loadDataWithRedirects(
      URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException {
    if (redirects >= MAXIMUM_REDIRECTS) {
      throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
    }
    //......
      //執行網絡請求
    urlConnection = connectionFactory.build(url);
    for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
      urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
    }
    urlConnection.setConnectTimeout(timeout);
    urlConnection.setReadTimeout(timeout);
    urlConnection.setUseCaches(false);
    urlConnection.setDoInput(true);
    urlConnection.setInstanceFollowRedirects(false);
    urlConnection.connect();
    stream = urlConnection.getInputStream();
    if (isCancelled) {
      return null;
    }
    final int statusCode = urlConnection.getResponseCode();
    if (isHttpOk(statusCode)) {
      //加載完成
      return getStreamForSuccessfulRequest(urlConnection);
    } else if (isHttpRedirect(statusCode)) {
      String redirectUrlString = urlConnection.getHeaderField("Location");
      if (TextUtils.isEmpty(redirectUrlString)) {
        throw new HttpException("Received empty or null redirect url");
      }
      URL redirectUrl = new URL(url, redirectUrlString);
      cleanup();
        //重定向
      return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
    } else if (statusCode == INVALID_STATUS_CODE) {
      throw new HttpException(statusCode);
    } else {
      throw new HttpException(urlConnection.getResponseMessage(), statusCode);
    }
  }

從上面的代碼中可以看到,在HttpUrlFetcher中執行了網絡請求加載數據。在完成加載後將數據流返回,然後調用callback.onDataReady(result),callback就是SourceGenerator。接下來的過程就是開始將加載好的數據流進行回傳。

第一步是SourceGenerator的onDataReady()方法。

public void onDataFetcherReady(
      Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
    cb.onDataFetcherReady(sourceKey, data, fetcher,  loadData.fetcher.getDataSource(), sourceKey);  //這裏的cb是DecodeJob
  }

在onDataReady()方法中通過callback回調onDataFetcherReady()方法。這裏的cb是DecodeJob。

public void onDataFetcherReady(
      Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
    //......
    if (Thread.currentThread() != currentThread) {
      runReason = RunReason.DECODE_DATA;
      callback.reschedule(this);
    } else {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        decodeFromRetrievedData();
      } finally {
        GlideTrace.endSection();
      }
    }
  }
private void decodeFromRetrievedData() {
    //......
    Resource<R> resource = null;
    try {
      resource = decodeFromData(currentFetcher, currentData, currentDataSource); //解碼資源
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
      notifyEncodeAndRelease(resource, currentDataSource); //通知
    } else {
      runGenerators();
    }
  }
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
	//......
    notifyComplete(result, dataSource); //資源準備完畢
    //......
  }

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

在DecodeJob中進一步完成回調,主要的工作是解碼資源,接下來繼續進行資源的回傳。這裏的callback時候EngineJob。

public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    synchronized (this) {
      this.resource = resource;
      this.dataSource = dataSource;
    }
    notifyCallbacksOfResult();
  }
  
  void notifyCallbacksOfResult() {
    ResourceCallbacksAndExecutors copy;
    Key localKey;
    EngineResource<?> localResource;
    synchronized (this) {
      stateVerifier.throwIfRecycled();
      if (isCancelled) {
          //如果是取消狀態,回收資源
        resource.recycle();
        release();
        return;
      } else if (cbs.isEmpty()) {
        throw new IllegalStateException("Received a resource without any callbacks to notify");
      } else if (hasResource) {
        throw new IllegalStateException("Already have resource");
      }
      engineResource = engineResourceFactory.build(resource, isCacheable, key, resourceListener);
     
      hasResource = true;
      copy = cbs.copy();
      incrementPendingCallbacks(copy.size() + 1);

      localKey = key;
      localResource = engineResource;
    }
    //這裏將資源加入了活動資源緩存
    engineJobListener.onEngineJobComplete(this, localKey, localResource);
	//這裏執行資源回調
    for (final ResourceCallbackAndExecutor entry : copy) {
      entry.executor.execute(new CallResourceReady(entry.cb));
    }
    decrementPendingCallbacks();
  }

CallResourceReady是EngineJob的內部類,主要作用是執行資源回調。

public void run() {
      synchronized (cb) {
        synchronized (EngineJob.this) {
          if (cbs.contains(cb)) {
            // Acquire for this particular callback.
            engineResource.acquire();
            callCallbackOnResourceReady(cb); //執行回調
            removeCallback(cb);
          }
          decrementPendingCallbacks();
        }
      }
    }

void callCallbackOnResourceReady(ResourceCallback cb) {
    try {
      cb.onResourceReady(engineResource, dataSource);
    } catch (Throwable t) {
      throw new CallbackException(t);
    }
  }

在這裏繼續執行資源回調。這裏的cb是SingleRequest。

public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
    stateVerifier.throwIfRecycled();
    loadStatus = null;
    //......
    Object received = resource.get();
    if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
      releaseResource(resource);
      onLoadFailed(exception);
      return;
    }
    //......
    onResourceReady((Resource<R>) resource, (R) received, dataSource);
  }

  private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
    boolean isFirstResource = isFirstReadyResource();
    status = Status.COMPLETE;
    this.resource = resource;

    isCallingCallbacks = true;
    try {
      boolean anyListenerHandledUpdatingTarget = false;
      if (requestListeners != null) {
        for (RequestListener<R> listener : requestListeners) {
          anyListenerHandledUpdatingTarget |=
              listener.onResourceReady(result, model, target, dataSource, isFirstResource);
        }
      }
      anyListenerHandledUpdatingTarget |=
          targetListener != null
              && targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);

      if (!anyListenerHandledUpdatingTarget) {
        Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
        target.onResourceReady(result, animation); //這個target是上面講到的持有ImageView的Target
      }
    } finally {
      isCallingCallbacks = false;
    }

    notifyLoadSuccess();
  }

從代碼中可以看到,這裏調用了Target對象。這裏的Target對象就是上面講到的持有ImageView的Target對象。這裏的Target是DrawableImageViewTarget,但是onResourceReady在ImageViewTarget中實現。

/**ImageViewTarget**/
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
    //在transition方法中設置圖片
    if (transition == null || !transition.transition(resource, this)) {
      setResourceInternal(resource);
    } else {
      maybeUpdateAnimatable(resource);
    }
  }
/**DrawableCrossFadeTransition**/
public boolean transition(Drawable current, ViewAdapter adapter) {
    Drawable previous = adapter.getCurrentDrawable();
    if (previous == null) {
      previous = new ColorDrawable(Color.TRANSPARENT);
    }
    TransitionDrawable transitionDrawable =
        new TransitionDrawable(new Drawable[] {previous, current});
    transitionDrawable.setCrossFadeEnabled(isCrossFadeEnabled);
    transitionDrawable.startTransition(duration);
    adapter.setDrawable(transitionDrawable); //設置圖片
    return true;
  }

至此,Glide就完成了整個圖片回調的流程了。

總結

可以看到,一行簡單的代碼 Glide.with(this).load(url).into(imageView);卻有着極其複雜的邏輯。這也反映了Glide的功能強大。

在上面的整個加載流程中,涉及到看各個方面。不同類型的圖片不同的加載方式,以及緩存的處理等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章