走進Glide的世界


文章篇幅較多.建議配合源碼閱讀并且有空閑時間去理解

Glide基本使用

 
RequestOptions options = new RequestOptions()
                        .placeholder(R.mipmap.ic_launcher) //占位圖
                        .error(R.mipmap.ic_launcher)//加載失敗圖
                        .circleCrop();//圓形
                Glide.with(this) //初始化Glide Glide的生命周期
                        .load(beans.get(0).getData().get(position).getImagePath())//圖片地址
                        .apply(options) //添加請求的參數(shù)
                        .centerCrop()//圖片加載樣式
                        .into(imageView);//加載的View

基本概念

  • Model 類型
  • Data 輸入流
  • Resource 解碼后資源
  • TransformedResource 轉(zhuǎn)換后的資源
  • TranscodedResource 轉(zhuǎn)碼完成后的資源
  • Target 顯示目標

with方法

傳入的context對象表示當(dāng)前Glide的加載生命周期,如果傳入Activity時調(diào)用onDestroy方法當(dāng)前Glide加載的圖片就會銷毀

  • 得到一個RequestManager 主要用來控制整個界面的生命周期
  • RequestManagerRetriever 是用來生產(chǎn)RequestManager
  • RequestManagerFragment 無界面的Fragment用來綁定生命周期
  public static RequestManager with(@NonNull Context context) {
    //返回一個RequestManagerRetriever象
  // 獲取一個 RequestManagerRetriever 描述一個圖片加載請求的管理者
    return getRetriever(context).get(context);
  }
//
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
   //...檢查Glide是否初始化
    //得到一個glide對象 通過glide得到一個RequestManager  在glide構(gòu)造方法中
    return Glide.get(context).getRequestManagerRetriever(); 
  }

RequestManagerRetriever

得到一個requestManagerRetriever對象,并且這里還需要返回一個Glide實例

public class Glide implements ComponentCallbacks2 {
  private static volatile Glide glide; 
  private static volatile boolean isInitializing; //是否初始化
  //單例得到Glide
    public static Glide get(@NonNull Context context) {
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context);
        }
      }
    }
    return glide;
  }
  private static void checkAndInitializeGlide(@NonNull Context context) {
   
    if (isInitializing) {
     //如果已經(jīng)初始化 拋出異常
    }
    isInitializing = true;
    initializeGlide(context); //初始化Glide
    isInitializing = false;
  }
    private static void initializeGlide(@NonNull Context context) {
      //GlideBuilder來初始化Glide
    initializeGlide(context, new GlideBuilder());
  }
  //初始化Glide
   private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
    Context applicationContext = context.getApplicationContext(); //得到當(dāng)前的Application
     //獲取 @GlideModule 注解驅(qū)動生成的 GeneratedAppGlideModuleImpl和GeneratedAppGlideModuleFactory 類
    GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
     //返回一個空的collections的集合
    List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
     //判斷@GlideModule的類是否為空或者是在Manifest中去注解isManifestParsingEnabled默認情況下返回True
    if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
        //通過Manifest中去得到GlideModule模塊
      manifestModules = new ManifestParser(applicationContext).parse();
    }
        //當(dāng)返回的GlideModule注解不為空并且注解生成的類模塊不為空
    if (annotationGeneratedModule != null
        && !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
      //得到當(dāng)前的GlideModule注解模塊
      Set<Class<?>> excludedModuleClasses =
          annotationGeneratedModule.getExcludedModuleClasses();
      //通過iterator來循環(huán)
      Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
      while (iterator.hasNext()) {
        //得到當(dāng)前的注解模塊
        com.bumptech.glide.module.GlideModule current = iterator.next();
        //如果已經(jīng)排除的模塊不包含當(dāng)前的類,結(jié)束本次循環(huán)
        if (!excludedModuleClasses.contains(current.getClass())) {
          continue;
        }
        if (Log.isLoggable(TAG, Log.DEBUG)) {
          Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
        }
        //如果包含當(dāng)前類 則移除這個類
        iterator.remove();
      }
    }

    if (Log.isLoggable(TAG, Log.DEBUG)) {
      for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
        Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());
      }
    }
    //嘗試從注解生成的 annotationGeneratedModule 中獲取 RequestManager 的構(gòu)造工廠對象
    RequestManagerRetriever.RequestManagerFactory factory =
        annotationGeneratedModule != null
            ? annotationGeneratedModule.getRequestManagerFactory() : null;
   //設(shè)置當(dāng)前的請求管理工廠
    builder.setRequestManagerFactory(factory);
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
      module.applyOptions(applicationContext, builder);
    }
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.applyOptions(applicationContext, builder);
    }
     //構(gòu)建Glide實體對象
    Glide glide = builder.build(applicationContext);
     //循環(huán)mainFast注解注冊的模塊 Glide3 版本通用的注冊模式 V4版本不再使用
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
      try {
        //嘗試去注冊Glide  ||得到注冊的生命周期, Glide對象 ,注冊管理器,包含注冊編碼,解碼和編碼的邏輯
        module.registerComponents(applicationContext, glide, glide.registry);
      } catch (AbstractMethodError e) {
        throw new IllegalStateException(
            "Attempting to register a Glide v3 module. If you see this, you or one of your"
                + " dependencies may be including Glide v3 even though you're using Glide v4."
                + " You'll need to find and remove (or update) the offending dependency."
                + " The v3 module name is: " + module.getClass().getName(), e);
      }
    } 
     //如果當(dāng)前annotationGeneratedModule 注解的模塊不為空
    if (annotationGeneratedModule != null) {
      //注冊Glide組件
      annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
    }
     //把Glide綁定到glide傳進來的生命周期中 用于檢測系統(tǒng) Config 改變和內(nèi)存占用量低的信號
    applicationContext.registerComponentCallbacks(glide);
     //存在靜態(tài)的成員變量中
    Glide.glide = glide;
  }
}

Glide的構(gòu)建過程

public final class GlideBuilder {
   
  private final Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions = new ArrayMap<>();
  //管理線程池的引擎
  private Engine engine;
  //享元復(fù)用池
  private BitmapPool bitmapPool;
  private ArrayPool arrayPool;
  //線程池
  private GlideExecutor sourceExecutor;
  private GlideExecutor diskCacheExecutor;
  private GlideExecutor animationExecutor;
  //磁盤緩存
  private DiskCache.Factory diskCacheFactory;
  //內(nèi)存緩存
  private MemorySizeCalculator memorySizeCalculator;
  private MemoryCache memoryCache;
  //連接監(jiān)視器
  private ConnectivityMonitorFactory connectivityMonitorFactory;
  //請求構(gòu)造器
  private RequestOptions defaultRequestOptions = new RequestOptions();
  //請求構(gòu)建工廠
  @Nullable
  private RequestManagerFactory requestManagerFactory;
  //是否保留Activity中的資源
  private boolean isActiveResourceRetentionAllowed;
  //請求監(jiān)聽器
  @Nullable
  private List<RequestListener<Object>> defaultRequestListeners;
  
   @NonNull
  Glide build(@NonNull Context context) {
    if (sourceExecutor == null) {
      //網(wǎng)絡(luò)使用連接池
      sourceExecutor = GlideExecutor.newSourceExecutor();
    }

    if (diskCacheExecutor == null) {
      //磁盤緩存連接池
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    }

    if (animationExecutor == null) {
      //執(zhí)行動畫池
      animationExecutor = GlideExecutor.newAnimationExecutor();
    }

    if (memorySizeCalculator == null) {
      //描述一個內(nèi)存的計算器, 智能加載圖片的大小, 判斷其需要的內(nèi)存空間
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    }

    if (connectivityMonitorFactory == null) {
      //默認的連接監(jiān)聽工廠
      connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
    }
        //bitMap的復(fù)用池
    if (bitmapPool == null) {
      int size = memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) {
        bitmapPool = new LruBitmapPool(size);
      } else {
        bitmapPool = new BitmapPoolAdapter();
      }
    }
        //數(shù)組復(fù)用池
    if (arrayPool == null) {
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }
        //資源緩存池
    if (memoryCache == null) {
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }
        //次盤緩存工廠
    if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }
        //構(gòu)建了一個負責(zé)管理線程池與緩存的執(zhí)行引擎
    if (engine == null) {
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(),
              animationExecutor,
              isActiveResourceRetentionAllowed);
    }
        //默認請求監(jiān)聽器
    if (defaultRequestListeners == null) {
      defaultRequestListeners = Collections.emptyList();
    } else {
      defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
    }
        //一個 RequestManagerRetriever 對象
    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);
    //構(gòu)建一個Glide對象
    return new Glide(
        context, //上下文環(huán)境
        engine,//執(zhí)行引擎
        memoryCache,//內(nèi)存緩存
        bitmapPool,//bitMap的復(fù)用池
        arrayPool,//數(shù)組復(fù)用池
        requestManagerRetriever,//請求管理類
        connectivityMonitorFactory,//連接監(jiān)聽器
        logLevel,//log等級
        defaultRequestOptions.lock(),//默認請求選項
        defaultTransitionOptions,//默認的轉(zhuǎn)換選項
        defaultRequestListeners,//默認的請求監(jiān)聽
        isLoggingRequestOriginsEnabled);//是否開啟請求資源的日志
  }
}

Glide 對象的構(gòu)建過程異常的復(fù)雜, 筆者調(diào)整了部分的數(shù)據(jù), 它們的流程如下

  • 構(gòu)建線程池 ------>根據(jù)不同的任務(wù)構(gòu)建不同的線程池
  • 構(gòu)建內(nèi)存緩存策略 ----> 1.內(nèi)存計算器 2. Lru緩存算法
  • 構(gòu)建對象復(fù)用池
  • 構(gòu)建工廠類 -->創(chuàng)了一個RequestManagerRetriever對象的工廠
  • 構(gòu)建 Glide 執(zhí)行引擎 ----->用于管理線程池和緩存
  • 創(chuàng)建 Glide 對象
    • Glide Builder 中的數(shù)據(jù)導(dǎo)入
    • 構(gòu)建一個 registry, 注冊了眾多的編解碼器
    • 構(gòu)建了一個 Glide Context 對象, 描述其數(shù)據(jù)資源的上下文

從 Glide 構(gòu)造的流程中, 可以看到它主要有五個核心部分, 線程池, 內(nèi)存緩存策略, 對象復(fù)用策略和圖片 ,音視頻的編解碼

??在創(chuàng)建GlideBuilder.build中, 我們看到了它 new 了一個RequestManagerRetriever 對象并且傳遞到了 Glide 對象內(nèi)部, 于是通過 Glide.getRequestManagerRetriever就可以很方便的獲取到 RequestManagerRetriever這個對象了

??獲取到了 RequestManagerRetriever 實例后, 接下來就可以通過 RequestManagerRetriever.get() 方法獲取 RequestManager 對象了

得到RequestManager

public class RequestManagerRetriever implements Handler.Callback {
  if (context == null) {
      throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {
        //下面是判斷當(dāng)前的Context的載體
      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());
      }
    }
  //若不在 MainThread 或 context 為 Application 的類型, 則使用 ApplicationManager
    return getApplicationManager(context);
}
  • RequestManagerRetriever.get 方法會判斷 Context 的類型
    • 若在主線程并且不為 Application類型的 Context 則找尋其依賴的 Activity
    • 若非主線程或為 Application 類型的 Context, 則使用 ApplicationManage
獲取ActivityRequestManager
  public RequestManager get(@NonNull Activity activity) {
    //判斷是否在子線程
    if (Util.isOnBackgroundThread()) {
      //子線程返回Application對象的RequestManager
      return get(activity.getApplicationContext());
    } else {
      //主線程
      assertNotDestroyed(activity); //不能在銷毀Activity時候去加載
      android.app.FragmentManager fm = activity.getFragmentManager();//獲取其 FragmentManager
      return fragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }
private RequestManager fragmentGet(@NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
  //1. 從 Activity 中獲取一個 RequestManagerFragment, 用于監(jiān)管 Activity 的聲明周期
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
   // 2. 獲取 Fragment 中保存的當(dāng)前頁面的請求管理器 
    RequestManager requestManager = current.getRequestManager();
   // 3. 不存在則創(chuàng)建一個請求管理器保存在 RequestManagerFragment 中
    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);
      current.setRequestManager(requestManager);
    }
  //返回這個請求管理器
    return requestManager;
  }
// 描述一個即將被 FragmentManager 添加的 RequestManagerFragment 緩存
  final Map<android.app.FragmentManager, RequestManagerFragment> pendingRequestManagerFragments =
      new HashMap<>();
private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
   //1 嘗試從 FragmentManager 中獲取這個 Fragment
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
   //2 不存在則添加一個
  if (current == null) {
    //3 從 pendingRequestManagerFragments 緩存中獲取一個
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        //3.1 創(chuàng)建并更新到緩存
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        if (isParentVisible) {
          //執(zhí)行Glide生命周期的start
          current.getGlideLifecycle().onStart();
        }
        //3.2 添加到等待被添加的緩存中因為添加到 FragmentManager 有延遲, 用這種方式防止同一時間創(chuàng)建了兩個 RequestManagerFragment 對象添加到 Activity 中
        pendingRequestManagerFragments.put(fm, current);
        //3.3 添加到 FragmentManager 中
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        //3.4 添加到 FragmentManager 成功, 通過 Handler 移除這個緩存
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

??可以看到 RequestManagerRetrieverget方法主要是在 Activity頁面中添加一個RequestManagerFragment 實例, 以便用于監(jiān)聽Activity的生命周期, 然后給這個 Fragment 注入一個RequestManager, 其處理的細節(jié)代碼中也注釋的比較詳細

  • 其中有個非常引人注目的細節(jié), 考慮到將 FragmentManger添加 Fragment有延遲, 為了防止同一時間創(chuàng)建了兩個 RequestManagerFragment 添加到 FragmentManager, 因此它使用了pendingRequestManagerFragments 進行緩存
獲取 ApplicationRequestManager
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) {
          //構(gòu)建Glide對象
          Glide glide = Glide.get(context.getApplicationContext());
          //得到RequestManager對象
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(),
                  new EmptyRequestManagerTreeNode(),
                  context.getApplicationContext());
        }
      }
    }
    return applicationManager;
  }

關(guān)于with方法總結(jié)

至此 with方法全部結(jié)束簡單總結(jié)一下

  • 構(gòu)建 Glide 實例
  • 獲取 RequestManagerRetriever 對象
  • 構(gòu)建 RequestManager 對象
    • 若可以綁定 Activity, 則為Activity 添加一個 RequestManagerFragment, 其內(nèi)部含有ReqeustManager 對象, 以便后續(xù)直接根據(jù) Activity的生命周期管控Glide 請求的處理
    • 若非可綁定 Activity, 則獲取一個單例的applicationManager專門用于處理這類請求

Load方法(RequestManager)

public class RequestManager implements LifecycleListener,
    ModelTypes<RequestBuilder<Drawable>> { 
      //load
            public RequestBuilder<Drawable> load(@Nullable String string) {
             return asDrawable().load(string);
          }
      // 構(gòu)建一個 RequestBuilder,描述一個目標資源為 Drawable 的圖片加載請求
       public RequestBuilder<Drawable> asDrawable() {
          return as(Drawable.class);
        }
        @NonNull
          @CheckResult
             public <ResourceType> RequestBuilder<ResourceType> as(
                      @NonNull Class<ResourceType> resourceClass) {
          return new RequestBuilder<>(glide, this, resourceClass, context);
        }
    }
  • load方法()
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>
    implements Cloneable,
    ModelTypes<RequestBuilder<TranscodeType>> {

       private Object model;//描述已經(jīng)加載的資源
        // 描述這個請求是否已經(jīng)添加了加載的數(shù)據(jù)源
        private boolean isModelSet;
        public RequestBuilder<TranscodeType> load(@Nullable String string) {
                return loadGeneric(string);
                 }
      private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
           this.model = model;
           isModelSet = true;
           return this;
         }
      
    }

Into方法(RequestBuilder)

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    Util.assertMainThread(); //檢測是否是主線程
    Preconditions.checkNotNull(view); //檢測View是否為空
     //根據(jù) view 的 scaleType 重構(gòu) RequestOptions RequestBuilder 直接繼承了 BaseRequestOptions
    BaseRequestOptions<?> requestOptions = this;
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      switch (view.getScaleType()) {
        case CENTER_CROP:
          // 1.1 克隆原 RequestOptions, 配置一個 CenterCrop 的縮放選項
          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.
      }
    }
// 2. 調(diào)用 into 方法, 創(chuàng)建并且執(zhí)行請求
    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions,
        Executors.mainThreadExecutor());
  }

可以看到 into 方法中

  • 第一步是根據(jù) ImageViewScaleType 來配置 Options 選項
  • 第二步調(diào)用了重載方法into執(zhí)行后續(xù)構(gòu)建請求操作

配置 Options

public abstract class BaseRequestOptions<T extends BaseRequestOptions<T>> implements Cloneable {
  ...
    public T optionalCenterCrop() {
    //optionalTransform   DownsampleStrategy 描述降采樣壓縮的策略 CenterCrop 描述圖像變化方式
    return optionalTransform(DownsampleStrategy.CENTER_OUTSIDE, new CenterCrop());
  }
 
    final T optionalTransform(@NonNull DownsampleStrategy downsampleStrategy,
      @NonNull Transformation<Bitmap> transformation) {
    if (isAutoCloneEnabled) {
      return clone().optionalTransform(downsampleStrategy, transformation);
    }
        //2. 將降采樣壓縮策略添加到 options 中
    downsample(downsampleStrategy);
     // 3. 將圖像變化方式添加到 transformations 中
    return transform(transformation, /*isRequired=*/ false);
  }
     //壓縮策略
    public T downsample(@NonNull DownsampleStrategy strategy) {
      //調(diào)用了 set, 將降采樣策略保存到 options 中
    return set(DownsampleStrategy.OPTION, Preconditions.checkNotNull(strategy));
  }
    public <Y> T set(@NonNull Option<Y> option, @NonNull Y value) {
    if (isAutoCloneEnabled) {
      return clone().set(option, value);
    }
            
    Preconditions.checkNotNull(option);
    Preconditions.checkNotNull(value);
    // 2.2 添加到 options 緩存中
    options.set(option, value);
    return selfOrThrowIfLocked();
  }
  
  T transform(
      @NonNull Transformation<Bitmap> transformation, boolean isRequired) {
    if (isAutoCloneEnabled) {
      return clone().transform(transformation, isRequired);
    }
        // 3.1 調(diào)用了 transform 的重載方法, 將這個圖像變化的方式作用到多種資源類型上
    DrawableTransformation drawableTransformation =
        new DrawableTransformation(transformation, isRequired);
    transform(Bitmap.class, transformation, isRequired);//Bitmap類型資源
    transform(Drawable.class, drawableTransformation, isRequired);//Drawable類型資源
    transform(BitmapDrawable.class, drawableTransformation.asBitmapDrawable(), isRequired);//BitmapDrawable類型資源
    transform(GifDrawable.class, new GifDrawableTransformation(transformation), isRequired);//動圖資源
    return selfOrThrowIfLocked();
  }
  private Map<Class<?>, Transformation<?>> transformations = new CachedHashCodeArrayMap<>();
  
  <Y> T transform(@NonNull Class<Y> resourceClass, @NonNull Transformation<Y> transformation,
      boolean isRequired) {
    if (isAutoCloneEnabled) {
      return clone().transform(resourceClass, transformation, isRequired);
    }

    Preconditions.checkNotNull(resourceClass);//空檢測
    Preconditions.checkNotNull(transformation);//空檢測
    // 3.2 添加到了 transformations 緩存中
    transformations.put(resourceClass, transformation);
    fields |= TRANSFORMATION;
    isTransformationAllowed = true;
    fields |= TRANSFORMATION_ALLOWED;
    isScaleOnlyOrNoTransform = false;
    if (isRequired) {
      fields |= TRANSFORMATION_REQUIRED;
      isTransformationRequired = true;
    }
    return selfOrThrowIfLocked();
  }
}

可以看到配置縮放選項的操作除了添加了圖像變化操作, 還設(shè)定了采樣方式, 分別保存在 transformations 和 options 中

構(gòu)建 Request請求

return into(glideContext.buildImageViewTarget(view, transcodeClass),
            // 2.1 調(diào)用 GlideContext.buildImageViewTarget 構(gòu)建一個 ViewTarget
            requestOptions,
        Executors.mainThreadExecutor());

我們知道 GlideContext是在 Glide 對象構(gòu)造時一并創(chuàng)建的, 它是 Context的裝飾者對象, 在 Application類型的 Context 中, 添加了 Glide 相關(guān)的數(shù)據(jù), 我們先看看它是如何構(gòu)建 ViewTarget

public class GlideContext extends ContextWrapper {
    public <X> ViewTarget<ImageView, X> buildImageViewTarget(
      @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
      //  調(diào)用工廠類來創(chuàng)建一個 imageView 的 ViewTarget
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
  }
}
public class ImageViewTargetFactory {
  @NonNull
  @SuppressWarnings("unchecked")
  public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
      @NonNull Class<Z> clazz) {
    // 根據(jù)目標編碼的類型來創(chuàng)建不同的 ViewTarget 對象, 因為我們沒有 asBitmap, 因此這里為 Drawable
    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)");
    }
  }
}

可以看到 GlideContext中通過工廠類創(chuàng)建了ImageViewViewTarget 的, 它描述的是圖像處理結(jié)束之后, 最終要作用到的 View 目標

構(gòu)建好了ViewTarge, 接下來就可以分析重載的into方法了, 看看它是如何構(gòu)建請求的

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()");
    }
    // 調(diào)用 buildRequest 構(gòu)建了一個 request 請求
    Request request = buildRequest(target, targetListener, options, callbackExecutor);
        // 處理這個 ViewTarget 之前的請求與新請求的沖突
    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);
    // 調(diào)用了請求 RequestManager.track 方法執(zhí)行請求
    requestManager.track(target, request);

    return target;
  }

可以看到調(diào)用了buildRequest構(gòu)建了一個 Glide 的請求, 其構(gòu)建過程也非常有意思, 最終最調(diào)用SingleRequest.obtain構(gòu)建一個Request 的實例對象, 之后便是調(diào)用 RequestManager.track將其分發(fā)并執(zhí)行了

Into的總結(jié)

  • 根據(jù) ImageView 構(gòu)建采樣壓縮和圖像變化的策略保存在 OptionsTransform
  • 構(gòu)建 ViewTarget 描述這個請求要作用的 View 對象
  • 構(gòu)建 Request 請求并執(zhí)行
    圖1.png

獲取數(shù)據(jù)源

在上面的into方法中我們已經(jīng)成功構(gòu)建一個Request 這里我們繼續(xù)往下看

  synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);//跟蹤生命周期
    requestTracker.runRequest(request);//開始請求數(shù)據(jù)
  }
 public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      //開始執(zhí)行請求
      request.begin();
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }


public final class SingleRequest<R> implements Request,
    SizeReadyCallback,
    ResourceCallback,
    FactoryPools.Poolable {
     public synchronized void begin() {
    ....
      //完成狀態(tài)
    if (status == Status.COMPLETE) {
      onResourceReady(resource, DataSource.MEMORY_CACHE);
      return;
    }
        //等待狀態(tài)
    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      //表示尺寸準備好了
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      target.getSize(this);
    }
    ....
  }
   public synchronized void onSizeReady(int width, int height) {
    ...
      //通過引擎的load方法構(gòu)造請求
    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);

   ....
  }
    }

任務(wù)的構(gòu)建(load)

public synchronized <R> LoadStatus load( ...) {
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
        //根據(jù)傳入的參數(shù), 構(gòu)建這個請求的 key
    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);
         // 2. 嘗試從 ActiveResources 緩存中查找這個 key 的緩存
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      // 若緩存存在, 則直接回調(diào) onResourceReady 處理后續(xù)操作
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }
        //嘗試從 LruResourceCache 中找尋這個資源 
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      // 回調(diào) onResourceReady 處理后續(xù)操作
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }
    //從緩存中查找 key 對應(yīng)的任務(wù)
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
      //走到這里說明這個任務(wù)已經(jīng)正在執(zhí)行了, 無需再次構(gòu)建執(zhí)行
      current.addCallback(cb, callbackExecutor);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      //返回加載狀態(tài)即可
      return new LoadStatus(cb, current);
    }
    //構(gòu)建一個新的引擎任務(wù)
    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);
    //構(gòu)建解碼任務(wù)
    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);
        //添加到任務(wù)緩存
    jobs.put(key, engineJob);
        //添加回調(diào)監(jiān)聽器
    engineJob.addCallback(cb, callbackExecutor);
    //執(zhí)行任務(wù)
    engineJob.start(decodeJob);
    return new LoadStatus(cb, engineJob);
  }

Load方法的作用是:

  • 構(gòu)建這個請求的key

  • 從緩存中查找key 對應(yīng)的資源, 若存在直接回 onResourceReady 表示資源準備好了

  • 從緩存中查找key對應(yīng)的任務(wù)

  • 若存在則說明無需再次獲取資源

  • 不存在需要構(gòu)建新的任務(wù)

    • 構(gòu)建引擎任務(wù) EngineJob
    • 引擎的任務(wù)為解碼任務(wù) DecodeJob
    • 將任務(wù)添加到緩存, 防止多次構(gòu)建
    • 執(zhí)行任務(wù)

任務(wù)執(zhí)行(start)

 public synchronized void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor(); //獲取線程池
    executor.execute(decodeJob); //執(zhí)行線程池
  }
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
    Runnable,
    Comparable<DecodeJob<?>>,
    Poolable {
      public void run() {
    GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
    DataFetcher<?> localFetcher = currentFetcher;
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      //調(diào)用runWrapped
      runWrapped();
    } catch (CallbackException e) {
      ...
  }
 private void runWrapped() {
    switch (runReason) {
      case INITIALIZE:
        //獲取任務(wù)的場景
        stage = getNextStage(Stage.INITIALIZE);
        //獲取這個場景的執(zhí)行者
        currentGenerator = getNextGenerator();
         // 執(zhí)行者執(zhí)行任務(wù)
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }   
        //獲取任務(wù)的場景
private Stage getNextStage(Stage current) {
    switch (current) {
      case INITIALIZE:
        //若我們配置的緩存策略允許從 資源緩存 中讀數(shù)據(jù), 則返回 Stage.RESOURCE_CACHE
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
      case RESOURCE_CACHE:
        //若我們配置的緩存策略允許從 源數(shù)據(jù)緩存中讀數(shù)據(jù), 則返回 Stage.DATA_CACHE
        return diskCacheStrategy.decodeCachedData()
            ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
      case DATA_CACHE:
        // 若只能允許從緩存中獲取數(shù)據(jù), 則直接 FINISH, 否則返回 Stage.SOURCE, 意為加載一個新的資源
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
  }
        //獲取這個場景的執(zhí)行者
  private DataFetcherGenerator getNextGenerator() {
    switch (stage) {
      case RESOURCE_CACHE:
        //資源磁盤緩存的執(zhí)行者
        return new ResourceCacheGenerator(decodeHelper, this);
      case DATA_CACHE:
        //源數(shù)據(jù)磁盤緩存的執(zhí)行者
        return new DataCacheGenerator(decodeHelper, this);
      case SOURCE:
        //無緩存, 獲取數(shù)據(jù)的源的執(zhí)行者
        return new SourceGenerator(decodeHelper, this);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized stage: " + stage);
    }
  }
        //執(zhí)行者執(zhí)行任務(wù)
  private void runGenerators() {
    currentThread = Thread.currentThread();//得到當(dāng)前線程
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    //currentGenerator.startNext()執(zhí)行請求操作
    while (!isCancelled && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);//得到下一個任務(wù)
      currentGenerator = getNextGenerator();//得到下一個任務(wù)的執(zhí)行者

      if (stage == Stage.SOURCE) {
        //重新調(diào)度任務(wù)
        reschedule();
        return;
      }
    }
  }
    }

DecodeJob 任務(wù)執(zhí)行時, 它根據(jù)不同的場景, 獲取不同的場景執(zhí)行器, 然后調(diào)用了它們的 startNext 方法加載請求任務(wù)的數(shù)據(jù), 其映射表為

場景 場景描述 場景執(zhí)行器
Stage.RESOURCE_CACHE 從磁盤中緩存的資源中獲取數(shù)據(jù) ResourceCacheGenerator
Stage.DATA_CACHE 從磁盤中緩存的源數(shù)據(jù)中獲取數(shù)據(jù) DataCacheGenerator
Stage.SOURCE 重新請求數(shù)據(jù) SourceGenerator

我們知道在 Engine 中, 嘗試從內(nèi)存緩存中獲取資源, 而 DecodeJob 則是嘗試從磁盤緩存中獲取資源, 我們這里主要查看 SourceGenerator.startNext 是如何加載請求任務(wù)的數(shù)據(jù)的

獲取源數(shù)據(jù)(startNext)

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()) {
      // 1. 從 DecodeHelper 的數(shù)據(jù)加載集合中, 獲取一個數(shù)據(jù)加載器
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        //2. 使用加載器中 fetcher 執(zhí)行數(shù)據(jù)加載
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

SourceGenerator 主要有兩步

  • 調(diào)用DecodeHelper.getLoadData獲取當(dāng)前請求的數(shù)據(jù)加載器
  • 調(diào)用加載器中的fetcher.loadData真正的執(zhí)行數(shù)據(jù)加載
獲取數(shù)據(jù)加載器
 List<LoadData<?>> getLoadData() {
    if (!isLoadDataSet) {
      isLoadDataSet = true;
      loadData.clear();
      // 1. 從 Glide 注冊的 register 中獲取請求 model 加載器
      List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
     // 遍歷每一個 modelLoaders 
      for (int i = 0, size = modelLoaders.size(); i < size; i++) {
        // 2. 通過 modelLoaders 構(gòu)建 loadData
        ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
        LoadData<?> current =
            modelLoader.buildLoadData(model, width, height, options);
        if (current != null) {
          // 添加到緩存
          loadData.add(current);
        }
      }
    }
    return loadData;
  }
  • 它會找到一個 ModelLoader 的實現(xiàn)類, 通過這個實現(xiàn)類的handles 方法, 判斷是否可以加載這個 model
  • 這里我們的 model以網(wǎng)絡(luò)的 URL 資源舉例, 它的實現(xiàn)類為HttpGlideUrlLoader 我們看看它如何構(gòu)建一個 LoadData對象的
- HttpGlideUrlLoader.java

public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,
      @NonNull Options options) {.
    GlideUrl url = model;
    if (modelCache != null) {
      url = modelCache.get(model, 0, 0);
      if (url == null) {
        modelCache.put(model, 0, 0, model);
        url = model;
      }
    }
    int timeout = options.get(TIMEOUT);
     // 創(chuàng)建了一個 LoadData 對象, 并且實例化了一個 HttpUrlFetcher 給它
    return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
  }

好的, 可以看到對于 URL 的加載, 其 fetcher 為一個 HttpUrlFetcher的實例, 接下來我們看看數(shù)據(jù)加載的流程

執(zhí)行數(shù)據(jù)加載
- HttpUrlFetcher.java
 @Override
  public void loadData(@NonNull Priority priority,
      @NonNull DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    try {
      // 獲取網(wǎng)絡(luò)圖片, 內(nèi)部使用了 HttpConnection 實現(xiàn), 僅僅做了重定向的處理
      //loadDataWithRedirects 內(nèi)部采用HttpConnection 實現(xiàn)
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
     // 將 inputStream 回調(diào)出去
      callback.onDataReady(result);
    } catch (IOException e) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "Failed to load data for url", e);
      }
      callback.onLoadFailed(e);
    } finally {
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
      }
    }
  }

數(shù)據(jù)加載的過程也是很簡單的, HttpUrlFetcher 它使用了 HttpConnection 發(fā)起了網(wǎng)絡(luò)請求, 獲取了數(shù)據(jù)流, 至此數(shù)據(jù)資源的獲取就已經(jīng)完成了, 后面要做的便是最重要的數(shù)據(jù)處理了, 它通過回調(diào)的方式將 InputStream扔了出去, 最終會回溯到 DecodeJobonDataFetcherReady 這個方法中

總結(jié)

走到這里, 一個請求的數(shù)據(jù)源獲取就已經(jīng)完成, 還剩下對數(shù)據(jù)源的處理操作, 一次 Glide 數(shù)據(jù)加載就完成了, 我們先回顧一下這次加載的流程圖

優(yōu)先從 memoryCache 中獲取 (內(nèi)存)

  • ActiveResource
  • LruResourceCache

次優(yōu)先從diskCache 中獲取 (磁盤)

  • Resource 資源緩存
  • Data 源數(shù)據(jù)緩存

執(zhí)行新的加載任務(wù)獲取源數(shù)據(jù) (網(wǎng)絡(luò)請求)

  • 通過 SourceGenerator 獲取數(shù)據(jù)
  • 通過 HttpUrlFetcher 獲取網(wǎng)絡(luò)數(shù)據(jù)流
圖2.png

數(shù)據(jù)源的處理

 DecodeJob.java
 
@Override
  public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
      DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;//保存數(shù)據(jù)的 key
    this.currentData = data;//保存數(shù)據(jù)的實體
    this.currentFetcher = fetcher;//保存數(shù)據(jù)的獲取器
    this.currentDataSource = dataSource;//數(shù)據(jù)來源: url 為 REMOTE 類型的枚舉, 表示從遠程獲取
    this.currentAttemptingKey = attemptedKey;//嘗試解碼的key
    if (Thread.currentThread() != currentThread) { //不是主線程
      runReason = RunReason.DECODE_DATA;
      callback.reschedule(this);//線程調(diào)度
    } else {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");//開啟跟蹤
      try {
        //嘗試解析數(shù)據(jù)
        decodeFromRetrievedData();
      } finally {
        GlideTrace.endSection();//結(jié)束
      }
    }
  }

private void decodeFromRetrievedData() {
    ...
    Resource<R> resource = null;
    try {
      //解析數(shù)據(jù)
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
      //解析成功,通知外界資源解析成功
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }

資源的獲取

 private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data,
      DataSource dataSource) throws GlideException {
    try {
      if (data == null) {
        return null;
      }
      long startTime = LogTime.getLogTime();
      //解析數(shù)據(jù)
      Resource<R> result = decodeFromFetcher(data, dataSource);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Decoded result " + result, startTime);
      }
      return result;
    } finally {
      fetcher.cleanup();
    }
  }
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
      throws GlideException {
     // 獲取當(dāng)前數(shù)據(jù)類的解析器 LoadPath
    LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
    //   通過解析器來解析來解析數(shù)據(jù)
    return runLoadPath(data, dataSource, path);
  }
private <Data, ResourceType> Resource<R> runLoadPath(Data data, DataSource dataSource,
      LoadPath<Data, ResourceType, R> path) throws GlideException {
    Options options = getOptionsWithHardwareConfig(dataSource);
  //根據(jù)數(shù)據(jù)類型獲取一個數(shù)據(jù)重造器, 獲取的數(shù)據(jù)為 InputStream, 因此它是一個 InputStreamRewinder 的實例
    DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
    try {
      // 將解析資源的任務(wù)轉(zhuǎn)移到了 LoadPath.load 方法中
      return path.load(
          rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
    } finally {
      rewinder.cleanup();
    }
  }

可以看到為了解析數(shù)據(jù), 首先構(gòu)建了一個 LoadPath, 然后創(chuàng)建了一個 InputStreamRewinder 類型的 DataRewinder, 最終將數(shù)據(jù)解析的操作到了 LoadPath.load 方法中

public Resource<Transcode> load(DataRewinder<Data> rewinder, @NonNull Options options, int width,
      int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException {
    List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire());
    try {
      return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
    } finally {
      listPool.release(throwables);
    }
  }

 private Resource<Transcode> loadWithExceptionList(DataRewinder<Data> rewinder,
      @NonNull Options options,
      int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback,
      List<Throwable> exceptions) throws GlideException {
    Resource<Transcode> result = null;
    //遍歷內(nèi)部存儲的 DecodePath 集合, 通過他們來解析數(shù)據(jù)
    for (int i = 0, size = decodePaths.size(); i < size; i++) {
      DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i);
      try {
        //調(diào)用 DecodePath.decode 真正進行數(shù)據(jù)的解析
        result = path.decode(rewinder, width, height, options, decodeCallback);
      } catch (GlideException e) {
        exceptions.add(e);
      }
      if (result != null) {
        break;
      }
    }
    if (result == null) {
      throw new GlideException(failureMessage, new ArrayList<>(exceptions));
    }
    return result;
  }

  public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
      @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
    //1. 調(diào)用 decodeResource 將源數(shù)據(jù)解析成中間資源
    Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
    //2. 調(diào)用 DecodeCallback.onResourceDecoded 處理中間資源
    Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
    //3. 調(diào)用 ResourceTranscoder.transcode 將中間資源轉(zhuǎn)為目標資源
    return transcoder.transcode(transformed, options);
  }

 private Resource<ResourceType> decodeResource(DataRewinder<DataType> rewinder, int width,
      int height, @NonNull Options options) throws GlideException {
    List<Throwable> exceptions = Preconditions.checkNotNull(listPool.acquire());
    try {
      //調(diào)用了 decodeResourceWithList
      return decodeResourceWithList(rewinder, width, height, options, exceptions);
    } finally {
      listPool.release(exceptions);
    }
  }

 private Resource<ResourceType> decodeResourceWithList(DataRewinder<DataType> rewinder, int width,
      int height, @NonNull Options options, List<Throwable> exceptions) throws GlideException {
    Resource<ResourceType> result = null;
    for (int i = 0, size = decoders.size(); i < size; i++) {
      ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
      try {
        DataType data = rewinder.rewindAndGet();
        if (decoder.handles(data, options)) {
          data = rewinder.rewindAndGet();
          // 調(diào)用 ResourceDecoder.decode 解析源數(shù)據(jù)
          result = decoder.decode(data, width, height, options);
        }
      } catch (IOException | RuntimeException | OutOfMemoryError e) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
          Log.v(TAG, "Failed to decode data for " + decoder, e);
        }
        exceptions.add(e);
      }

      if (result != null) {
        break;
      }
    }
    if (result == null) {
      throw new GlideException(failureMessage, new ArrayList<>(exceptions));
    }
    return result;
  }

可以看到數(shù)據(jù)解析的任務(wù)最重是通過 DecodePath來執(zhí)行的, 它內(nèi)部有三個操作

  • 調(diào)用decodeResource 將源數(shù)據(jù)解析成資源
    • 源數(shù)據(jù): InputStream
    • 中間產(chǎn)物: Bitmap
  • 調(diào)用 DecodeCallback.onResourceDecoded 處理資源
  • 調(diào)用ResourceTranscoder.transcode將資源轉(zhuǎn)為目標資源
    • 目標資源類型: Drawable
1. 解析源數(shù)據(jù)
StreamBitmapDecoder.java
public Resource<Bitmap> decode(@NonNull InputStream source, int width, int height,
      @NonNull Options options)
      throws IOException {
    final RecyclableBufferedInputStream bufferedStream;
    final boolean ownsBufferedStream;
   ...
    ExceptionCatchingInputStream exceptionStream =
        ExceptionCatchingInputStream.obtain(bufferedStream);
    MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream);
    UntrustedCallbacks callbacks = new UntrustedCallbacks(bufferedStream, exceptionStream);
    try {
      //   根據(jù)請求配置的數(shù)據(jù), 對數(shù)據(jù)流進行采樣壓縮, 獲取到一個 Resource<Bitmap>
      return downsampler.decode(invalidatingStream, width, height, options, callbacks);
    } finally {
      exceptionStream.release();
      if (ownsBufferedStream) {
        bufferedStream.release();
      }
    }
  }
Downsampler.java
public Resource<Bitmap> decode(InputStream is, int requestedWidth, int requestedHeight,
      Options options, DecodeCallbacks callbacks) throws IOException {
    Preconditions.checkArgument(is.markSupported(), "You must provide an InputStream that supports"
        + " mark()");

    byte[] bytesForOptions = byteArrayPool.get(ArrayPool.STANDARD_BUFFER_SIZE_BYTES, byte[].class);
    BitmapFactory.Options bitmapFactoryOptions = getDefaultOptions();
    bitmapFactoryOptions.inTempStorage = bytesForOptions;

    DecodeFormat decodeFormat = options.get(DECODE_FORMAT);
    DownsampleStrategy downsampleStrategy = options.get(DownsampleStrategy.OPTION);
    boolean fixBitmapToRequestedDimensions = options.get(FIX_BITMAP_SIZE_TO_REQUESTED_DIMENSIONS);
    boolean isHardwareConfigAllowed =
      options.get(ALLOW_HARDWARE_CONFIG) != null && options.get(ALLOW_HARDWARE_CONFIG);

    try {
      Bitmap result = decodeFromWrappedStreams(is, bitmapFactoryOptions,
          downsampleStrategy, decodeFormat, isHardwareConfigAllowed, requestedWidth,
          requestedHeight, fixBitmapToRequestedDimensions, callbacks);
      //用線程池把流轉(zhuǎn)為Resource<Bitmap>
      return BitmapResource.obtain(result, bitmapPool);
    } finally {
      releaseOptions(bitmapFactoryOptions);
      byteArrayPool.put(bytesForOptions);
    }
  }

可以看到它內(nèi)部通過Downsampler.decode方法對數(shù)據(jù)流進行采樣壓縮, 來獲取這個流的Bitmap

  • 這個采樣的策略就是我們在構(gòu)建 Request時傳入的, 其采樣壓縮的細節(jié), 并不是我們本次關(guān)注的重點

我們看看獲取到了 Resource 之后, 如何處理這個資源

2. 資源的處理

可以看到, 當(dāng)我們將源數(shù)據(jù)解析成對應(yīng)的資源之后, 便會調(diào)用 DecodeCallback.onResourceDecoded 處理資源, 我們看看它

的處理過程

 @Override
    public Resource<Z> onResourceDecoded(@NonNull Resource<Z> decoded) {
      return DecodeJob.this.onResourceDecoded(dataSource, decoded);
    }
<Z> Resource<Z> onResourceDecoded(DataSource dataSource,
      @NonNull Resource<Z> decoded) {
    @SuppressWarnings("unchecked")
  //1. 獲取數(shù)據(jù)資源的類型
    Class<Z> resourceSubClass = (Class<Z>) decoded.get().getClass();
    Transformation<Z> appliedTransformation = null;
    Resource<Z> transformed = decoded;
  //2. 若非從資源磁盤緩存中獲取的數(shù)據(jù)源, 則對資源進行 transformation 操作
    if (dataSource != DataSource.RESOURCE_DISK_CACHE) {
      appliedTransformation = decodeHelper.getTransformation(resourceSubClass);
      transformed = appliedTransformation.transform(glideContext, decoded, width, height);
    }
    if (!decoded.equals(transformed)) {
      decoded.recycle();
    }
        // 3. 構(gòu)建數(shù)據(jù)編碼的策略
    final EncodeStrategy encodeStrategy;
    final ResourceEncoder<Z> encoder;
    if (decodeHelper.isResourceEncoderAvailable(transformed)) {
      encoder = decodeHelper.getResultEncoder(transformed);
      encodeStrategy = encoder.getEncodeStrategy(options);
    } else {
      encoder = null;
      encodeStrategy = EncodeStrategy.NONE;
    }
     //4. 根據(jù)編碼策略, 構(gòu)建緩存的 key   
    Resource<Z> result = transformed;
    boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey);
    if (diskCacheStrategy.isResourceCacheable(isFromAlternateCacheKey, dataSource,
        encodeStrategy)) {
      if (encoder == null) {
        throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass());
      }
      final Key key;
      switch (encodeStrategy) {
        case SOURCE://  源數(shù)據(jù)的 key
          key = new DataCacheKey(currentSourceKey, signature);
          break;
        case TRANSFORMED:   // 資源數(shù)據(jù)的 key
          key =
              new ResourceCacheKey(
                  decodeHelper.getArrayPool(),
                  currentSourceKey,
                  signature,
                  width,
                  height,
                  appliedTransformation,
                  resourceSubClass,
                  options);
          break;
        default:
          throw new IllegalArgumentException("Unknown strategy: " + encodeStrategy);
      }
    //  5. 初始化編碼管理者, 用于提交內(nèi)存緩存
      LockedResource<Z> lockedResult = LockedResource.obtain(transformed);
      deferredEncodeManager.init(key, encoder, lockedResult);
      result = lockedResult;
    }
  //  返回 transform 之后的 bitmap
    return result;
  }

可以看到 onResourceDecoded 中, 主要是對中間資源做了如下的操作

  • 對資源進行 transformed操作
    • 將資源轉(zhuǎn)為目標效果, 如在構(gòu)建request 時, 設(shè)置的 CenterCrop
  • 構(gòu)建磁盤緩存的 key
3. 將數(shù)據(jù)轉(zhuǎn)為目標格式

目標數(shù)據(jù)為 Drawable, 因此它的轉(zhuǎn)換器為 BitmapDrawableTranscoder

BitmapDrawableTranscoder .java
  @Override
  public Resource<BitmapDrawable> transcode(@NonNull Resource<Bitmap> toTranscode,
      @NonNull Options options) {
  //調(diào)用了 LazyBitmapDrawableResource.obtain 獲取 Resource<BitmapDrawable> 的實例對象
    return LazyBitmapDrawableResource.obtain(resources, toTranscode);
  }
LazyBitmapDrawableResource.java
 public static Resource<BitmapDrawable> obtain(
      @NonNull Resources resources, @Nullable Resource<Bitmap> bitmapResource) {
    if (bitmapResource == null) {
      return null;
    }
  //創(chuàng)建了一個 LazyBitmapDrawableResource
    return new LazyBitmapDrawableResource(resources, bitmapResource);

  }
 private LazyBitmapDrawableResource(@NonNull Resources resources,
      @NonNull Resource<Bitmap> bitmapResource) {
    this.resources = Preconditions.checkNotNull(resources);
    this.bitmapResource = Preconditions.checkNotNull(bitmapResource);
  }
  @Override
  public BitmapDrawable get() {
    // Get 方法反回了一個 BitmapDrawable 對象
    return new BitmapDrawable(resources, bitmapResource.get());
  }

好的, 轉(zhuǎn)化成目標數(shù)據(jù)也非常的簡單, 它將我們解析到的bitmap 存放到 LazyBitmapDrawableResource 內(nèi)部, 然后外界通過 get 方法就可以獲取到一個 BitmapDrawable 的對象了

4. 解碼轉(zhuǎn)換結(jié)構(gòu)圖
圖3.png

數(shù)據(jù)的展示

DecodeJob.java
private void decodeFromRetrievedData() {
    ...
    Resource<R> resource = null;
    try {
    // 解析 inputStream 獲取資源 
      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) {
    if (resource instanceof Initializable) {
      ((Initializable) resource).initialize();
    }
        
    Resource<R> result = resource;
    LockedResource<R> lockedResource = null;
    if (deferredEncodeManager.hasResourceToEncode()) {
      lockedResource = LockedResource.obtain(resource);
      result = lockedResource;
    }
        // 回調(diào)上層資源
    notifyComplete(result, dataSource);

    stage = Stage.ENCODE;
    try {
    // 將數(shù)據(jù)緩存到磁盤
      if (deferredEncodeManager.hasResourceToEncode()) {
        deferredEncodeManager.encode(diskCacheProvider, options);
      }
    } finally {
      if (lockedResource != null) {
        lockedResource.unlock();
      }
    }
    // Call onEncodeComplete outside the finally block so that it's not called if the encode process
    // throws.
    onEncodeComplete();
  }
  private void notifyComplete(Resource<R> resource, DataSource dataSource) {
    setNotifiedOrThrow();
    //從 DecodeJob 的構(gòu)建中, 我們知道這個 Callback 是一 EngineJob
    callback.onResourceReady(resource, dataSource);
  }
   @Override
  public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    synchronized (this) {
      this.resource = resource;
      this.dataSource = dataSource;
    }
    notifyCallbacksOfResult();
  }

DecodeJob.decodeFromRetrievedData 中, 主要做了兩個操作

  • 回調(diào)EngineJob.onResourceReady 資源準備好了
  • 將數(shù)據(jù)緩存到磁盤
EngineJob.java
void notifyCallbacksOfResult() {
    ResourceCallbacksAndExecutors copy;
    Key localKey;
    EngineResource<?> localResource;
    ...
        // 1. 通知上層 Engine 任務(wù)完成了
    engineJobListener.onEngineJobComplete(this, localKey, localResource);
        //回調(diào)給 ImageViewTarget 展示資源
    for (final ResourceCallbackAndExecutor entry : copy) {
      entry.executor.execute(new CallResourceReady(entry.cb));
    }
    decrementPendingCallbacks();
  }
  • EngineJob 中也是有兩步操作, 一個是通知上層任務(wù)完成了, 另一個是回調(diào)給 ImageViewTarget展示資源
Engine .java 
public synchronized void onEngineJobComplete(
      EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
    // A null resource indicates that the load failed, usually due to an exception.
    if (resource != null && resource.isMemoryCacheable()) {
      // 將加載好的資源添加到內(nèi)存緩存
      activeResources.activate(key, resource);
    }
    jobs.removeIfCurrent(key, engineJob);
  }

我們知道在請求發(fā)起前是Engine嘗試通過內(nèi)存緩存讀, 結(jié)束之后再回到 Engine 添加內(nèi)存緩存也不足為奇了

ImageViewTarget.java
  @Override
  public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
    if (transition == null || !transition.transition(resource, this)) {
      setResourceInternal(resource);// 處理一些 transition 變化,
    } else {
      maybeUpdateAnimatable(resource);
    }
  }
   private void setResourceInternal(@Nullable Z resource) {
    // Order matters here. Set the resource first to make sure that the Drawable has a valid and
    // non-null Callback before starting it.
    setResource(resource);
    maybeUpdateAnimatable(resource);
  }
  
 DrawableImageViewTarget .java
 @Override
  protected void setResource(@Nullable Drawable resource) {
    view.setImageDrawable(resource);
  }

ImageViewTarget 調(diào)用了子類重寫的 setResource 方法, 將數(shù)據(jù)填充進去, 至此一次Glide圖像加載就完成了

流程回顧

圖5.png

通過一次流程分析我們得知, 整個Glide 圖片加載主要有如下幾步

  • 請求管理器的構(gòu)建
    • 一個 Context對應(yīng)一個 RequestManager
  • 請求的構(gòu)建
    • 請求的寬高、采樣的方式、transform 變化...
  • 通過請求獲取資源
    • Engine 從內(nèi)存緩存中查找
      • ActiveResources 緩存中查找
      • LruResourceCache 緩存中查找
    • 內(nèi)存緩存不存在, 則構(gòu)建任務(wù)執(zhí)行
      • 構(gòu)建一個EngineJob 描述一個請求任務(wù), 任務(wù)類型為 DecodeJob
        • DecodeJobdiskCache 中查找
        • diskCache不存在, 則通過網(wǎng)絡(luò)請求, 獲取數(shù)據(jù)源
        • 通過 Downsampler解析源數(shù)據(jù)并進行采樣壓縮獲取 Bitmap
        • Bitmap 進行 transform處理
          • 構(gòu)建磁盤緩存的key
        • transform 之后的 Bitmap 轉(zhuǎn)為Resource 回傳給上層
          • DecodeJob 進行磁盤緩存
    • Engine 對資源進行內(nèi)存緩存
  • 傳遞給View 進行展示

看了 Glide 的加載流程, 我似乎能夠明白為什么他是 Google 推薦的圖片加載框架了, 內(nèi)部細節(jié)的處理做的非常的到位, 而且使用GlideContext用于描述Glide 的上下文, 與 Android 的 Context巧妙的融合在一起, 讀起來真有一種閱讀 Android 源碼的既視感

不過這只是最簡單的流程, 而且 Glide 支持 Gif, 視頻加載操作, 可想而知其內(nèi)部的 Decorder 處理了多少邏輯代碼, 如此復(fù)雜的流程, 嵌套了如此之多的回調(diào), 無疑增加了我們閱讀源碼的難度, 若是將這些操作分層, 并且使用攔截器去實現(xiàn), 我想定會讓一次圖像加載操作變得更加清晰明了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容