Glide的简单梳理

Posted 清浅岁月

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Glide的简单梳理相关的知识,希望对你有一定的参考价值。

#Glide

Glide的使用

   implementation 'com.github.bumptech.glide:glide:4.8.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'

简单的使用

RequestOptions options =new RequestOptions().centerCrop();
                
Glide.with(this).load("").apply(options).into(imageview)

Glide 图片加载流程

Glide的intoc传的参数有Target和ImagView,其实图片ImagView最后也会变成一个Target,通过glideContext.buildImageViewTarget


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

    RequestOptions requestOptions = this.requestOptions;
    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) 
      // Clone in this method so that if we use this RequestBuilder to load into a View and then
      // into a different target, we don't retain the transformation applied based on the previous
      // View's scale type.
      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),
        /*targetListener=*/ null,
        requestOptions);
  

这个是传递CustomViewTarget的参数的方法:
最终都是Target的形式处理的。


  private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @NonNull RequestOptions options) 
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) 
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    

    options = options.autoClone();
    Request request = buildRequest(target, targetListener, options);

    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) 
      request.recycle();
      // If the request is completed, beginning again will ensure the result is re-delivered,
      // triggering RequestListeners and Targets. If the request is failed, beginning again will
      // restart the request, giving it another chance to complete. If the request is already
      // running, we can let it continue running without interruption.
      if (!Preconditions.checkNotNull(previous).isRunning()) 
        // Use the previous request rather than the new one to allow for optimizations like skipping
        // setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
        // that are done in the individual Request.
        previous.begin();
      
      return target;
    

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

    return target;
  

之后将Target转换成Request再处理,再Glide的build的时候指定默认的Request为singleRequest,Target转换成一个singleRequest去处理的。最终调用Request的begin开始处理图片。

singleRequest

public void begin() 
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    startTime = LogTime.getLogTime();
    if (model == null) 
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) 
        width = overrideWidth;
        height = overrideHeight;
      
      // Only log at more verbose log levels if the user has set a fallback drawable, because
      // fallback Drawables indicate the user expects null models occasionally.
      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 we're restarted after we're complete (usually via something like a notifyDataSetChanged
    // that starts an identical request into the same Target or View), we can simply use the
    // resource and size we retrieved the last time around and skip obtaining a new size, starting a
    // new load etc. This does mean that users who want to restart a load because they expect that
    // the view size has changed will need to explicitly clear the View or Target before starting
    // the new load.
    if (status == Status.COMPLETE) 
      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());
    
    if (IS_VERBOSE_LOGGABLE) 
      logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    
  

  onSizeReady(overrideWidth, overrideHeight);

看一下这个方法:

/**
   * A callback method that should never be invoked directly.
   */
  @Override
  public void onSizeReady(int width, int height) 
    stateVerifier.throwIfRecycled();
    if (IS_VERBOSE_LOGGABLE) 
      logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
    
    if (status != Status.WAITING_FOR_SIZE) 
      return;
    
    status = Status.RUNNING;

    float sizeMultiplier = requestOptions.getSizeMultiplier();
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

    if (IS_VERBOSE_LOGGABLE) 
      logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
    
    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);

    // This is a hack that's only useful for testing right now where loads complete synchronously
    // even though under any executor running on any thread but the main thread, the load would
    // have completed asynchronously.
    if (status != Status.RUNNING) 
      loadStatus = null;
    
    if (IS_VERBOSE_LOGGABLE) 
      logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    
  

真正开始的地方是这里:

engine.load里真正的开始加载的,调用的是Engine的load方法区获取的,Engine对象时在SingleRequest的obtain的时候 从glideContent中获取的,glideContent是从Glide初始化的时候new出来的,Engine也是。

看一下这里


   */
  public <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      boolean isScaleOnlyOrNoTransform,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean useAnimationPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb) 
    Util.assertMainThread();
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

	//  生成key

    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);
        
	// 从获取资源中获取,就是正在展示中的图片中加载
	
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) 
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) 
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      
      return null;
    

	// 从缓存资源中获取

    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) 
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (VERBOSE_IS_LOGGABLE) 
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      
      return null;
    
// 走到这里如果还没有获取到资源就需要网络加载获取

    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) 
      current.addCallback(cb);
      if (VERBOSE_IS_LOGGABLE) 
        logWithTimeAndKey("Added to existing load", startTime, key);
      
      return new LoadStatus(cb, current);
    

    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);

    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);

    jobs.put(key, engineJob);

    engineJob.addCallback(cb);
    engineJob.start(decodeJob);

    if (VERBOSE_IS_LOGGABLE) 
      logWithTimeAndKey("Started new load", startTime, key);
    
    return new LoadStatus(cb, engineJob);
  
  

稍微总结一下:

  1. loadFromActiveResources
  2. loadFromCache
  3. 从硬盘获取
  4. 从网络获取

1. loadFromActiveResources

下面看下一loadFromActiveResources是从ActiveResources中获取的:

 @Nullable
  EngineResource<?> get(Key key) 
    ResourceWeakReference activeRef = activeEngineResources.get(key);
    if (activeRef == null) 
      return null;
    

    EngineResource<?> active = activeRef.get();
    if (active == null) 
      cleanupActiveReference(activeRef);
    
    return active;
  
  
@VisibleForTesting
  final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();

activeEngineResources是一个hashmap,ResourceWeakReference弱引用处理的。

@VisibleForTesting
  static final class ResourceWeakReference extends WeakReference<EngineResource<?>> 
    @SuppressWarnings("WeakerAccess") @Synthetic final Key key;
    @SuppressWarnings("WeakerAccess") @Synthetic final boolean isCacheable;

    @Nullable @SuppressWarnings("WeakerAccess") @Synthetic Resource<?> resource;

    @Synthetic
    @SuppressWarnings("WeakerAccess")
    ResourceWeakReference(
        @NonNull Key key,
        @NonNull EngineResource<?> referent,
        @NonNull ReferenceQueue<? super EngineResource<?>> queue,
        boolean isActiveResourceRetentionAllowed) 
      super(referent, queue);
      this.key = Preconditions.checkNotNull(key);
      this.resource =
          referent.isCacheable() && isActiveResourceRetentionAllowed
              ? Preconditions.checkNotNull(referent.getResource()) : null;
      isCacheable = referent.isCacheable();
    

    void reset() 
      resource = null;
      clear();
    
  

2. loadFromCache

private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) 
    if (!isMemoryCacheable) 
      return null;
    

    EngineResource<?> cached = getEngineResourceFromCache(key);
    if (cached != null) 
      cached.acquire();
      activeResources.activate(key, cached);
    
    return cached;
  

看一下:
getEngineResourceFromCache

private EngineResource<?> getEngineResourceFromCache(Key key) 
    Resource<?> cached = cache.remove(key);

    final EngineResource<?> result;
    if (cached == null) 
      result = null;
     else if (cached instanceof EngineResource) 
      // Save an object allocation if we've cached an EngineResource (the typical case).
      result = (EngineResource<?>) cached;
     else 
      result = new EngineResource<>(cached, true /*isMemoryCacheable*/, true /*isRecyclable*/);
    
    return result;
  

将资源添加到ActiveResources中方便下次再次获取。getEngineResourceFromCache是从这里MemoryCache中获取的,MemoryCache是接口,坑定是从初始化设置的子类获取的。看一下Glide的初始化


  @NonNull
  Glide build(@NonNull Context context) 
    if (sourceExecutor == null) 
      sourceExecutor = GlideExecutor.newSourceExecutor();
    

    if (diskCacheExecutor == null) 
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    

    if (animationExecutor == null) 
      animationExecutor = GlideExecutor.newAnimationExecutor();
    

    if (memorySizeCalculator == null) 
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    

    if (connectivityMonitorFactory == null) 
      connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
    

    if (bitmapPool == null) 
      int size = memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) 
        bitmapPool = new LruBitmapPool(size);
       else 
        bitmapPool = new BitmapPoolAdapter();
      
    

    if (arrayPool == null) 
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    

// 这个就是
    if (memoryCache == null) 
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    

    if (diskCacheFactory == null) 
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    

    if (engine == null) 
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(),
              GlideExecutor.newAnimationExecutor(),
              isActiveResourceRetentionAllowed);
    

    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock(),
        defaultTransitionOptions);
  

在这里配置的内存缓存对象
if (memoryCache == null)
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());

LruResourceCache是继承LruCache,实现MemoryCache接口的。

看一下LruResourceCache 的remove方法,LruResourceCache中没有重写MemoryCache的remove的方法,直接是LruCache的remove方法,疑惑,为啥不直接用get要用remove的方法?

3. 从硬盘获取

在Engine的load中后面创建了,EngineJob,和decodeJob,EngineJob辅助Engine处理任务,
DecodeJob是一个实现了Runnable,最后调用的是EngineJob的start,嗲用线程池进行任务处理。

public void start(DecodeJob<R> decodeJob) 
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
  

再看一下DecodeJob的的Run方法怎么处理的,

@Override
  public void run() 
    // This should be much more fine grained, but since Java's thread pool implementation silently
    // swallows all otherwise fatal exceptions, this will at least make it obvious to developers
    // that something is failing.
    GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
    // Methods in the try statement can invalidate currentFetcher, so set a local variable here to
    // ensure that the fetcher is cleaned up either way.
    DataFetcher<?> localFetcher = currentFetcher;
    try 
      if (isCancelled) 
        notifyFailed();
        return;
      
      
      // 这里开始执行
      
      runWrapped();
     catch (Throwable t) 
      // Catch Throwable and not Exception to handle OOMs. Throwables are swallowed by our
      // usage of .submit() in GlideExecutor so we're not silently hiding crashes by doing this. We
      // are however ensuring that our callbacks are always notified when a load fails. Without this
      // notification, uncaught throwables never notify the corresponding callbacks, which can cause
      // loads to silently hang forever, a case that's especially bad for users using Futures on
      // background threads.
      if (Log.isLoggable(TAG, Log.DEBUG)) 
        Log.d(TAG, "DecodeJob threw unexpectedly"
            + ", isCancelled: " + isCancelled
            + ", stage: " + stage, t);
      
      // When we're encoding we've already notified our callback and it isn't safe to do so again.
      if (stage != Stage.ENCODE) 
        throwables.add(t);
        notifyFailed();
      
      if (!isCancelled) 
        throw t;
      
     finally 
      // Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call
      // close in all cases anyway.
      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);
    
  

看一下:

getNextGenerator();

runGenerators();
  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);
    
  

  private void runGenerators() 
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    while (!isCancelled && currentGenerator != null
        && !(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();
    

    // Otherwise a generator started a new load and we expect to be called back in
    // onDataFetcherReady.
  

网络请求在HttpGlideUrlLoader类中才开始,

 @Override
  public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,
      @NonNull Options options) 
    // GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time
    // spent parsing urls.
    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);
    return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
  

HttpUrlFetcher中通过HttpURLConnection进行网络处理的。

BitMapPool的使用

在into的流程中是没有会用到BitMapPool的,BitMapPool的使用主要是在transform中,图像的变化中,先从BitMapPool获取,没有在拿原始图片变换,变化完成之后再放到BitMapPool池中进行缓存。

public abstract class BitmapTransformation implements Transformation<Bitmap> 

  @NonNull
  @Override
  public final Resource<Bitmap> transform(
      @NonNull Context context, @NonNull Resource<Bitmap> resource, int outWidth, int outHeight) 
    if (!Util.isValidDimensions(outWidth, outHeight)) 
      throw new IllegalArgumentException(
          "Cannot apply transformation on width: " + outWidth + " or height: " + outHeight
              + " less than or equal to zero and not Target.SIZE_ORIGINAL");
    
    BitmapPool bitmapPool = Glide.get(context).getBitmapPool();
    Bitmap toTransform = resource.get();
    int targetWidth = outWidth == Target.SIZE_ORIGINAL ? toTransform.getWidth() : outWidth;
    int targetHeight = outHeight == Target.SIZE_ORIGINAL ? toTransform.getHeight() : outHeight;
    Bitmap transformed = transform(bitmapPool, toTransform, targetWidth, targetHeight);

    final Resource<Bitmap> result;
    if (toTransform.equals(transformed)) 
      result = resource;
     else 
      result = BitmapResource.obtain(transformed, bitmapPool);
    
    return result;
  

   protected abstract Bitmap transform(
      @NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight);


BitmapTransformation实现Transformation接口,而且是一个抽象类,其子类有CircleCrop,CenterCrop,FitCenter,RoundedCorners等圆形变化,圆角变化这些都是他的子类,自定义类型可以直接继承BitmapTransformation去处理。

看一下BitmapPool中是如何获取bitmap的,根据控件大缓存图片,BitmapPool是如何存放图片的:


  @Override
  public synchronized void put(Bitmap bitmap) 
    if (bitmap == null) 
      throw new NullPointerException("Bitmap must not be null");
    
    if (bitmap.isRecycled()) 
      throw new IllegalStateException("Cannot pool recycled bitmap");
    
    if (!bitmap.isMutable() || strategy.getSize(bitmap) > maxSize
        || !allowedConfigs.contains(bitmap.getConfig())) 
      if (Log.isLoggable(TAG, Log.VERBOSE)) 
        Log.v(TAG, "Reject bitmap from pool"
                + ", bitmap: " + strategy.logBitmap(bitmap)
                + ", is mutable: " + bitmap.isMutable()
                + ", is allowed config: " + allowedConfigs.contains(bitmap.getConfig()));
      
      bitmap.recycle();
      return;
    

    final int size = strategy.getSize(bitmap);
    strategy.put(bitmap);
    tracker.add(bitmap);

    puts++;
    currentSize += size;

    if (Log.isLoggable(TAG, Log.VERBOSE)) 
      Log.v(TAG, "Put bitmap in pool=" + strategy.logBitmap(bitmap));
    
    dump();

    evict();
  


是通过LruPoolStrategy缓存池策略决定的,有三种策略:SizeConfigStrategy,AttributeStrategy,SizeStrategy三种策略,根据版本在Glide的build文件中根据版本做了设置,4.0以上使用的是SizeConfigStrategy大小配置策略,看一下大小配置策略中谁如何存取的:

SizeConfigStrategy中put和get方法:



  @Override
  public void put(Bitmap bitmap) 
    int size = Util.getBitmapByteSize(bitmap);
    Key key = keyPool.get(size, bitmap.getConfig());

    groupedMap.put(key, bitmap);

    NavigableMap<Integer, Integer> sizes = getSizesForConfig(bitmap.getConfig());
    Integer current = sizes.get(key.size);
    sizes.put(key.size, current == null ? 1 : current + 1);
  

  @Override
  @Nullable
  public Bitmap get(int width, int height, Bitmap.Config config) 
    int size = Util.getBitmapByteSize(width, height, config);
    Key bestKey = findBestKey(size, config);

    Bitmap result = groupedMap.get(bestKey);
    if (result != null) 
      // Decrement must be called before reconfigure.
      decrementBitmapOfSize(bestKey.size, result);
      result.reconfigure(width, height,
          result.getConfig() != null ? result.getConfig() : Bitmap.Config.ARGB_8888);
    
    return result;
  


存取数据都是需要Key的,看一下去和获取到key:


private Key findBestKey(int size, Bitmap.Config config) 
    Key result = keyPool.get(size, config);
    for (Bitmap.Config possibleConfig : getInConfigs(config)) 
      NavigableMap<Integer, Integer> sizesForPossibleConfig = getSizesForConfig(possibleConfig);
      Integer possibleSize = sizesForPossibleConfig.ceilingKey(size);
      if (possibleSize != null && possibleSize <= size * MAX_SIZE_MULTIPLE) 
        if (possibleSize != size
            || (possibleConfig == null ? config != null : !possibleConfig.equals(config))) 
          keyPool.offer(result);
          result = keyPool.get(possibleSize, possibleConfig);
        
        break;
      
    
    return result;
  
  

根据Bitmap.Config获取到一组数据,再通过
关键在这里:

      NavigableMap<Integer, Integer> sizesForPossibleConfig = getSizesForConfig(possibleConfig);
  Integer possibleSize = sizesForPossibleConfig.ceilingKey(size);

SortMap的ceilingKey返回大于等于键的最小值,如果当前获取5x5的一张图片,缓存池中有一张6x6,7x7的将优先返回6x6的图片资源,所以通过复用之前的图片资源。

详细或者更全面的学习和了解移步大神博客

以上是关于Glide的简单梳理的主要内容,如果未能解决你的问题,请参考以下文章

Glide 4.12 框架源码中的生命周期设计

Glide 4.12 框架源码中的生命周期设计

Glide 4.12 框架源码中的生命周期设计

Glide 4.12 框架源码中的生命周期设计

Google图片加载库Glide的简单封装GlideUtils

Android Generaed API的使用(Glide更简单的用法)