Glide加載一張網圖時發生了啥

Glide.with(imageView.context).load(url).into(imageView)

這一串代碼是加載圖片的最簡形式.

分別傳遞了3個參數

  • context主要用于生成framgnet控制glide加載生命周期
  • 基于url生成key,找到緩存中對應的圖片資源
  • 有了圖片資源后,加載到imageView中

生命周期的控制——RequestManager

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

getRetriever中獲取glide的RequestManagerRetriever

  • 若glide為null,則會用單例模式構造
  • RequestManagerRetriever

RequestManagerRetriever中通過對context類型的判斷,生成RequestManagerFragment/SupportRequestManagerFragment.通過這個framgnet獲取生命周期和RequestManagerTreeNode,生成RequestManager

  • 這里的生命周期和androidX中的不是同一個,但作用類似
  • 同一個context只會生成一個RequestManagerFragment/SupportRequestManagerFragment,并且只有這一個RequestManager
RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory,
      Context context) {
    
        ...

    // If we're the application level request manager, we may be created on a background thread.
    // In that case we cannot risk synchronously pausing or resuming requests, so we hack around the
    // issue by delaying adding ourselves as a lifecycle listener by posting to the main thread.
    // This should be entirely safe.
    if (Util.isOnBackgroundThread()) {
      mainHandler.post(addSelfToLifecycle);
    } else {
      lifecycle.addListener(this);
    }
    lifecycle.addListener(connectivityMonitor);
        
        ...
  }

RequestManager本身繼承LifecycleListener,在構建的時候注冊監聽.

  • 除了注冊自身的監聽,還有個ConnectivityMonitor,在有網絡權限時,默認實現為DefaultConnectivityMonitor.DefaultConnectivityMonitor在接受到onStart事件時,會注冊一個監聽網絡狀態的廣播,onStop時注銷.當無網狀態切換到有網的時候,廣播便會執行requestTracker.restartRequests(),開始處理請求.

RequestManager的onStart和onStop方法中,會針對requestTracker和targetTracker這兩個對象操作

/**
   * Lifecycle callback that registers for connectivity events (if the
   * android.permission.ACCESS_NETWORK_STATE permission is present) and restarts failed or paused
   * requests.
   */
  @Override
  public synchronized void onStart() {
    resumeRequests();
    targetTracker.onStart();
  }

  /**
   * Lifecycle callback that unregisters for connectivity events (if the
   * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads.
   */
  @Override
  public synchronized void onStop() {
    pauseRequests();
    targetTracker.onStop();
  }
  • RequestTracker 負責跟蹤Request
  • TargetTracker 負責跟蹤Target

RequestTracker和TargetTracker都是對數組進行操作,既然是數組,通過查看對數組操作的函數,最后定位到RequestBuilder.into函數中

private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> options,
      Executor callbackExecutor) {
        
        Request request = buildRequest(target, targetListener, options, callbackExecutor);
        ...

    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
  }

加載請求的構建——RequestBuilder

在into方法中,構建了target與request

  • Target繼承LifecycleListener,會被TargetTracker控制;Target有很多實現,這里transcodeClass對應的是Drawable.class,生成DrawableImageViewTarget

    public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
        
            ...
    
        return into(
            glideContext.buildImageViewTarget(view, transcodeClass),
            /*targetListener=*/ null,
            requestOptions,
            Executors.mainThreadExecutor());
      }
    
    public class ImageViewTargetFactory {
      @NonNull
      @SuppressWarnings("unchecked")
      public <Z> ViewTarget<ImageView, Z> buildTarget(
          @NonNull ImageView view, @NonNull Class<Z> clazz) {
        if (Bitmap.class.equals(clazz)) {
          return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
        } else if (Drawable.class.isAssignableFrom(clazz)) {
          return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
        } else {
          throw new IllegalArgumentException(
              "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
        }
      }
    }
    
  • Request的基本實現是SingleRequest,同樣會被RequestTracker控制

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

上面構建Target時,之所以說transcodeClass == Drawable.class.是因為transcodeClass的類型由Glide.load函數決定的.

public RequestBuilder<Drawable> load(@Nullable Object model) {
    return asDrawable().load(model);
}
public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
      @NonNull Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
}

加載的邏輯

RequestManager的onStart執行時,初始status == Status.PENDING

public void begin() {
    synchronized (requestLock) {

            ...

      status = Status.WAITING_FOR_SIZE;
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        onSizeReady(overrideWidth, overrideHeight);
      } else {
        target.getSize(this);
      }

    }
  }

target.getSize(target為DrawableImageViewTarget,getSize為基類ViewTarget函數)→

SizeDeterminer.getSize(獲取寬高,若寬高無效,通過注冊ViewTreeObserver,在onPreDraw中獲取寬高,獲取到有效數據后,回調SingleRequest.onSizeReady)→

SingleRequest.onSizeReady→

Engine.load(這個時候會通過Glide.load等參數構建EngineKey,通過key去activeResources/cache中取數據)

  • activeResources 沒有大小限制.保存活躍的圖片資源.
  • cache 有大小限制.保存不展示的圖片資源
  • 受生命周期控制,當RequestManagerFragment/SupportRequestManagerFragment銷毀的時候,從activeResources中remove添加到cache中

→waitForExistingOrStartNewJob

  • 從activeResources/cache中沒取到數據時,則執行這個方法,如果任務已經存在,則不重復創建,只添加回調

  • 若任務不存在,則構建EngineJob和DecodeJob,并在EngineJob中啟動DecodeJob

    public synchronized void start(DecodeJob<R> decodeJob) {
        this.decodeJob = decodeJob;
        GlideExecutor executor =
            decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
        executor.execute(decodeJob);
      }
    
  • 這里利用線程池執行DecodeJob(DecodeJob本身繼承Runnable)

  • decodeJob.willDecodeFromCache() 會根據diskCacheStrategy來判斷使用那個線程池

    boolean willDecodeFromCache() {
        Stage firstStage = getNextStage(Stage.INITIALIZE);
        return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
    }
    
    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);
        }
      }
    
  • diskCacheStrategy對象得追溯到Glide構造的時候,有默認實現,也有set方法.共有5種類型,ALL/NONE/DATA/RESOURCE/AUTOMATIC.默認實現為AUTOMATIC.

    public final class GlideBuilder {
    
            private RequestOptionsFactory defaultRequestOptionsFactory =
          new RequestOptionsFactory() {
            @NonNull
            @Override
            public RequestOptions build() {
              return new RequestOptions();
            }
        };
    
            public GlideBuilder setDefaultRequestOptions(@Nullable final RequestOptions requestOptions) {
            return setDefaultRequestOptions(
            new RequestOptionsFactory() {
              @NonNull
              @Override
              public RequestOptions build() {
                return requestOptions != null ? requestOptions : new RequestOptions();
              }
            });
          }
    }
    
  • 通過上面的分析可知,當設置的DiskCacheStrategy == AUTOMATIC == RESOURCE == ALL的時候 firstStage == Stage.RESOURCE_CACHE. DiskCacheStrategy == DATA 時 firstStage == Stage.DATA_CACHE,便會啟動diskCacheExecutor.

    • 線程池數量為1
  • 只有DiskCacheStrategy == NONE,才會啟動getActiveSourceExecutor.useUnlimitedSourceGeneratorPool和useAnimationPool默認為false,則會啟動sourceExecutor

    • 線程池數量由CPU核心數決定,最小為4個
    private GlideExecutor getActiveSourceExecutor() {
        return useUnlimitedSourceGeneratorPool
            ? sourceUnlimitedExecutor
            : (useAnimationPool ? animationExecutor : sourceExecutor);
    }
    
    public static int calculateBestThreadCount() {
        if (bestThreadCount == 0) {
          bestThreadCount =
              Math.min(MAXIMUM_AUTOMATIC_THREAD_COUNT, RuntimeCompat.availableProcessors());
        }
        return bestThreadCount;
      }
    

DecodeJob執行完成后,會回調EngineJob.onResourceReady→

EngineJob.notifyCallbacksOfResult

  1. CallResourceReady.run()→SingleRequest.onResourceReady→target.onResourceReady→設置資源
  2. Engine.onEngineJobComplete(將資源存儲到activeResources中)

加載過程——DecodeJob

  • ResourceCacheGenerator 從內存中獲取數據
  • DataCacheGenerator 從本地緩存中獲取,并存儲到內存中
  • SourceGenerator 從網絡獲取圖片,并存儲到本地

run→

runWrapped(初始化時,runReason == INITIALIZE)→

getNextStage(根據diskCacheStrategy,更新Stage)→

getNextGenerator(根據stage,獲取需要執行的generator)→

runGenerators(while循環執行generator.startNext)→

reschedule(當循環到stage =SOURCE時執行,currentGenerator = SourceGenerator 。交給線程池,重新run)→

run→

runWrapped(runReason = SWITCH_TO_SOURCE_SERVICE)→

SourceGenerator.startNext(初始邏輯,獲取loadData中的fetcher,執行fetcher的加載邏輯,fetcher執行成功后)→

SourceGenerator.onDataReady→

DecodeJob.reschedule(重新調度)→

run→

runWrapped(runReason = SWITCH_TO_SOURCE_SERVICE)→

SourceGenerator.startNext(寫入本地文件邏輯)→

SourceGenerator.cacheData→

DataCacheGenerator.startNext(找到對應的LoadData,加載數據,加載完成執行callback onDataReady,再接口回調至SourceGenerator.onDataFetcherReady,再接口回調至DecodeJob.onDataFetcherReady)→

reschedule(runReason = RunReason.DECODE_DATA,重新調度)→

run→

runWrapped(runReason = SWITCH_TO_SOURCE_SERVICE)→

decodeFromRetrievedData→

decodeFromData(根據currentData類型,currentDataSource數據源類型,在Registry中找到對應的decoder和transcoder,并組建出decodePaths;根據decodePaths組建LoadPath;根據LoadPath獲取Resource<>,正常為LazyBitmapDrawableResource類型)→

notifyEncodeAndRelease→

notifyComplete→觸發EngineJob.onResourceReady

總結

  1. Glide在加載時,會生成全局唯一的glide和engine.
  2. 每個activity加載圖片時,都會額外創建一個不可見的fragmnt,用于控制生命周期,基于此生成requestManager.
  3. 每個加載請求都會生成target與request,target中收集了view信息及view資源類型.在target確認好view的寬高后,會通過request觸發engine的加載邏輯.
  4. engine會嘗試從activeResources和cache中加載數據,未成功,便會創建engineJob和decodeJob.
  5. engineJob會啟動decodeJob,嘗試從ResourceCacheGenerator/DataCacheGenerator/SourceGenerator中獲取數據.
  6. 取得數據后,便交由target設置資源,同時保存到engine的activeResources中.
  7. 當activity銷毀時,觸發生命周期銷毀邏輯,資源從activeResources中remove添加到cache中.

調試日志

adb shell setprop log.tag.Engine VERBOSE 根據打印內容判斷加載源

  • Started new load 磁盤或者網絡
  • Loaded resource from active resources
  • Loaded resource from cache

DecodeJob|Engine|OkHttpLoadImg|PrintingEventListener|SourceGenerator|loadImg

關閉日志 adb shell setprop log.tag.Engine ERROR

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。