Glide4.11源码分析(二)三级缓存之内存缓存

本文深入剖析了Glide的内存缓存机制,从RequestBuilder的load方法开始,详细解释了请求的创建、生命周期绑定、TargetTargetTracker以及内存缓存的获取过程。通过跟踪代码,展示了当加载数据时如何从内存缓存中查找资源,如果未找到则启动加载任务进入子线程执行。最后,讨论了内存缓存的两种形式ActiveResources和LruCache,并阐述了它们在缓存策略中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Glide4.11源码分析(一)生命周期的绑定
Glide4.11源码分析(二)三级缓存之内存缓存
Glide4.11源码分析(三)子线程执行的那些事儿及本地缓存

上文讲了Glide.with(activity)方法的流程,获取到了RequestManager对象,梳理出来了RequestManagerFragment生命周期绑定的过程。这篇文章我们看看看RequestManager的load过程。
RequestBuilder<Drawable> builder = requestManager.load("http://www.xxx.com/pic")
先看下返回的RequestBuilder是什么东西

> 代码片段9

//A generic class that can handle setting options and staring loads for generic resource types.
//Type parameters:
//<TranscodeType> – The type of resource that will be delivered to the Target.
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>
    implements Cloneable, ModelTypes<RequestBuilder<TranscodeType>> {
  //略..
  private final Context context;
  private final RequestManager requestManager;
  private final Class<TranscodeType> transcodeClass;
  //...略...
}

通用类,可以处理通用资源类型的设置选项和启动加载过程。RequestBuilder继承自BaseRequestOptions,传递的泛型类型是Target要价在的资源的类型。
看下RequestManager.load方法是如何获取RequestBuilder类对象的

> 代码片段10
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
 	return asDrawable().load(string);
}
/**
* 这个中调用as方法传递的是Drawable类对象
*/
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
  return as(Drawable.class);
}
@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(@NonNull Class<ResourceType> resourceClass) {
    //通过new创建RequestBuilder
  return new RequestBuilder<>(glide, this, resourceClass, context);
}

/**
* RequestBuilder构造方法 赋值成员变量transcodeClass 为上面传递过来的Drawable.class后面要用到
*/
protected RequestBuilder(@NonNull Glide glide, RequestManager requestManager,Class<TranscodeType> transcodeClass, Context context) {
    this.glide = glide;
    this.requestManager = requestManager;
    this.transcodeClass = transcodeClass;
    this.context = context;
    this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
    this.glideContext = glide.getGlideContext();
    //将RequestListener添加到requestListeners列表中
    initRequestListeners(requestManager.getDefaultRequestListeners());
    //设置选项
    apply(requestManager.getDefaultRequestOptions());
  }

RequestBuilder有了,然后调用了RequestBuilder的load方法,并最终调用它的loadGeneric方法,这个方法就是设置了成员变量model的值,此model就用来表示要加载的数据源。

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

此方法并没有直接加载图片,接着往下看placeholder方法

> 代码片段12

@CheckResult
public T placeholder(@DrawableRes int resourceId) {
  if (isAutoCloneEnabled) {//默认false,通过调用autoClone方法修改为true
    return clone().placeholder(resourceId);
  }
  //设置placeholderId
  this.placeholderId = resourceId;
  fields |= PLACEHOLDER_ID;

  placeholderDrawable = null;
  fields &= ~PLACEHOLDER;

  return selfOrThrowIfLocked();
}

if判断内部的逻辑是通过深拷贝获取一个builder副本。这里默认不会走if中判断,只是修改成员变量placeholderIdfields的值,并返回builder。接下来的error方法跟这个逻辑相同,继续往下走,看centerCrop方法:

> 代码片段13

@NonNull
@CheckResult
public T centerCrop() {
  //DownsampleStrategy.CENTER_OUTSIDE 就是CenterOutside 对象
  return transform(DownsampleStrategy.CENTER_OUTSIDE, new CenterCrop());
}

@CheckResult
final T transform(@NonNull DownsampleStrategy downsampleStrategy , @NonNull Transformation<Bitmap> transformation) {
  if (isAutoCloneEnabled) {
    return clone().transform(downsampleStrategy, transformation);
  }
  //这里设置option为CenterOutside类型的
  downsample(downsampleStrategy);
  //这里应用变换,其实有个变换集合transformations,会存储变换类型。这里就是存储了变换类型
  return transform(transformation);
}

接下来看into方法,上代码:

> 代码片段14
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
  ///略。。
  return into(
      glideContext.buildImageViewTarget(view, transcodeClass),
      /*targetListener=*/ null,
      requestOptions,//这个值是根据imageview的scaleType值,采用对应的requestOption
      Executors.mainThreadExecutor());
}

glideContext是调用Glide构造方法的时候创建的,transcodeClass参数就是我们在生成RequestBuilder的时候,调用as(Drawable.class)方法传进来的,忘记了的同学可以上去找一找。第4个参数Executors.mainThreadExecutor(),是一个创建了个主线程的线程池,需要展示的数据的时候用到,后面还会讲到。下面先看下glideContextbuildImageViewTarget方法:

> 代码片段15
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
	//imageViewTargetFactory是创建glideContext的时候new出来的
  return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}

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)");
  }
}

clazz就是前面调用as方法返回的结果,所以上面的buildTarget方法会走else if里面的逻辑 生成DrawableImageViewTarget对象并强转为ViewTarget,下面讲讲这个ViewTarget
1、首先ViewTarget间接实现了LifecycleListener接口,这个接口就是加载过程中的生命周期回调;
2、ViewTarget用来将Bitmap加载到View中,内部有个泛型T就是加载进去的目标类型,比如ImaeView;
3、ViewTarget还可以实现图片的复用,并通过View.setTag(Object object)方法来存储图片的源信息以达到复用的目的,比如在ListView中的复用;
4、ViewTarget中有两个方法分别是setRequest(Request request)getRequest()。如下

> 代码片段16
/**
 * 通过setTag来存储Request
 */
@Override
public void setRequest(@Nullable Request request) {
  setTag(request);
}

/**
 * 通过getTag获取存储在view的request
 * View尽量不要使用setTag,因为有可能导致Glide的一些问题,Glide使用setTag存储了请求
 */
@Override
@Nullable
public Request getRequest() {
  Object tag = getTag();
  Request request = null;
  if (tag != null) {
    if (tag instanceof Request) {
      request = (Request) tag;
    } else {
      throw new IllegalArgumentException(
          "You must not call setTag() on a view Glide is targeting");
    }
  }
  return request;
}

上面代码注释说的比较清楚,就是view会存储当前view的request。
好了,接着into方法跟进

> 代码片段18
private <Y extends Target<TranscodeType>> Y into(@NonNull Y target,@Nullable RequestListener<TranscodeType> targetListener,BaseRequestOptions<?> options,Executor callbackExecutor) {
	//获取request
    Request request = buildRequest(target, targetListener, options, callbackExecutor);
	//...略...
    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
  }

先看下buildRequest都做了什么工作,buildRequest方法内部会直接调用buildRequestRecursive

> 代码片段19
private Request buildRequestRecursive(Object requestLock,Target<TranscodeType> target,@Nullable RequestListener<TranscodeType> targetListener,@Nullable RequestCoordinator parentCoordinator,TransitionOptions<?, ? super TranscodeType> transitionOptions,Priority priority,int overrideWidth,int overrideHeight,BaseRequestOptions<?> requestOptions,Executor callbackExecutor) {
    // Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
    ErrorRequestCoordinator errorRequestCoordinator = null;
    if (errorBuilder != null) {
      errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    }
    Request mainRequest =
        buildThumbnailRequestRecursive(
            requestLock,
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions,
            callbackExecutor);

    if (errorRequestCoordinator == null) {
      return mainRequest;
    }

    int errorOverrideWidth = errorBuilder.getOverrideWidth();
    int errorOverrideHeight = errorBuilder.getOverrideHeight();
    if (Util.isValidDimensions(overrideWidth, overrideHeight) && !errorBuilder.isValidOverride()) {
      errorOverrideWidth = requestOptions.getOverrideWidth();
      errorOverrideHeight = requestOptions.getOverrideHeight();
    }

    Request errorRequest =
        errorBuilder.buildRequestRecursive(
            requestLock,
            target,
            targetListener,
            errorRequestCoordinator,
            errorBuilder.transitionOptions,
            errorBuilder.getPriority(),
            errorOverrideWidth,
            errorOverrideHeight,
            errorBuilder,
            callbackExecutor);
    errorRequestCoordinator.setRequests(mainRequest, errorRequest);
    return errorRequestCoordinator;
  }

上面这个方法就会判断使用Glide的时候是否调用了方法builder.error(RequestBuilder<TranscodeType> errorBuilder),这个是用来处理当builder请求失败以后,是否继续执行errorBuilder中的请求的过程。我们demo中没有设置这个,所以可以忽略这段逻辑,直接返回了第9行处的调用,继续往下看

> 代码片段20
private Request buildThumbnailRequestRecursive(Object requestLock,Target<TranscodeType> target,RequestListener<TranscodeType> targetListener,@Nullable RequestCoordinator parentCoordinator,TransitionOptions<?, ? super TranscodeType> transitionOptions,Priority priority,int overrideWidth,int overrideHeight,BaseRequestOptions<?> requestOptions,Executor callbackExecutor) {
    //略去与缩略图相关的请求设置
      // Base case: no thumbnail.
      return obtainRequest(
          requestLock,
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight,
          callbackExecutor);
    
  }

上面代码逻辑中我们省略了和缩略图请求相关的逻辑,直接obtainRequest方法。obtainRequest这个方法就是通过调用SingleRequestobtain的方法直接new了一个SingleRequest对象,方法内部没有额外的逻辑,在此就不贴代码了。
返回到代码片段18into方法中,request有了,接着往下走

//清除将要发生的加载过程释放资源
requestManager.clear(target);
//给当前view设置request,还记的前面讲的ViewTarget类里面的setTag和getTag方法吗,这里就会调用到,用以将request和view绑定
target.setRequest(request);
//追踪请求,其实就是开始加载数据
requestManager.track(target, request);

我们看下最后一句是怎么加载数据的

> 代码片段22 RequestManager.java
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
  targetTracker.track(target);
  requestTracker.runRequest(request);
}

上面分析过这个target就是DrawableImageViewTarget,而DrawableImageViewTarget继承自ImageViewTarget,而ImageViewTarget间接实现了LifecycleListener,并在onStart onStop方法中完成开启和停止动画的逻辑。
先看下targetTracker对象的类

public final class TargetTracker implements LifecycleListener {
  private final Set<Target<?>> targets =
      Collections.newSetFromMap(new WeakHashMap<Target<?>, Boolean>());

  public void track(@NonNull Target<?> target) {
    targets.add(target);
  }

  public void untrack(@NonNull Target<?> target) {
    targets.remove(target);
  }

  @Override
  public void onStart() {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onStart();
    }
  }

  @Override
  public void onStop() {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onStop();
    }
  }

  @Override
  public void onDestroy() {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onDestroy();
    }
  }
  //略
 }

TargetTracker类中维护着一个集合,保存了target,也就是用来展示图片的目标view。该类实现了LifecycleListener接口,并在响应的回调中调用Target的回调方法,例如上面说到的ImageViewTarget的回调去执行动画。
还记得上篇文章结尾讲到的RequestManageronStart和onStop方法吗?这两个方法中都会执行targetTracker.onStarttargetTracker.onStop方法。这样RequestManagerFragment的生命周期函数又和Target的生命周期绑定了。

再来总结下:上篇文章将到Glide创建的透明的Fragment的生命周期和RequestManager的生命周期绑定了,所以Fragment生命周期方法发生回调的时候,会调用RequestManager,而RequestManager的生命周期方法中会回调TargetTracker的生命周期方法,而TargetTracker的生命周期方法会遍历内部set集合并调用集合元素Target的生命周期方法,而这个集合就是通过targetTracker.track(target);方法添加的,集合元素Target的生命周期方法的内部会执行相应动画的开始和停止逻辑

接下来看代码片段22track方法的第二句代码,

//这里request是SingleRequest类的对象,上文已经分析过了
public void runRequest(@NonNull Request request) {
	//将请求加入队列
  requests.add(request);
  if (!isPaused) {
  //开始请求
    request.begin();
  } else {
  //如果isPasued 就清除请求
    request.clear();
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      Log.v(TAG, "Paused, delaying request");
    }
    //将请求加入pendingRequests队列
    pendingRequests.add(request);
  }
}

SingleRequest的begin方法法

public void begin() {
  synchronized (requestLock) {
    //略。。。
    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      onSizeReady(overrideWidth, overrideHeight);
    } else {
    	//注释5
      target.getSize(this);
    }
    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
        //这里会设置target的placeholder
      target.onLoadStarted(getPlaceholderDrawable());
    }
    //略。。。
  }
}

这个方法省略判空抛异常的判断,修改status,这个status负责记录加载过程中的状态,第一个if判断了,如果Glide设置了overrideWidthoverrideHeight属性,也就是使用过程中调用了override方法,就会进入判断并调用onSizeReady方法,这个方法后面还会看到,这里先不讲。我们使用的时候没设置ovrride、所以看注释5的 else逻辑调用target.getSize(this);这个方法传递的参数是this,也就是SingleRequest对象,这个对象实现了SizeReadyCallback接口

com.bumptech.glide.request.target.ViewTarget.SizeDeterminer.java

void getSize(@NonNull SizeReadyCallback cb) {
  int currentWidth = getTargetWidth();
  int currentHeight = getTargetHeight();
  //注释6
  if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
    cb.onSizeReady(currentWidth, currentHeight);
    return;
  }

  // We want to notify callbacks in the order they were added and we only expect one or two
  // callbacks to be added a time, so a List is a reasonable choice.
  if (!cbs.contains(cb)) {
    cbs.add(cb);
  }
  if (layoutListener == null) {
  //如果目标view没有设置具体的宽高,就会给getViewTreeObserver设置一个监听
  //此监听就是当onPreDraw系统方法回调的时候,去获取view的宽高
  //获取到的话,回调SingleRequest的onSizeReady方法
    ViewTreeObserver observer = view.getViewTreeObserver();
    layoutListener = new SizeDeterminerLayoutListener(this);
    observer.addOnPreDrawListener(layoutListener);
  }
}

target.getSize(this);这代码中target是DrawableImageViewTarget类型对象,而他又间接实现了ViewTarget所以这里getSize其实就是ViewTarget中的方法,然后会调用到ViewTarget的内部类SizeDeterminer中的getSize方法,也就是上面这段代码,看下这段代码中注释6处的判断,这里判断的是View的宽高是否合法,如果View的宽高设置的wrap_content,则这里获取的值为0,然后跳过判断往下走、否则进入判断中的逻辑。先说下宽高取值为0的情况,这种情况下会把SizeReadyCallback对象,也就是前面传进来的SingleRequest对象添加到一个List集合cbs对象里,然后获取ViewTreeObserver对象并给这个对象添加OnPreDrawListener监听,这个监听是在view树将要开始绘制之前触发的,有兴趣的可以跟进SizeDeterminerLayoutListener类的onPreDraw的方法看一下,这里的处理逻辑就是获取view宽高、然后遍历cbs集合,分别调用他们的onSizeReady方法;而注释6处的判断如果成立,则直接调用onSizeReady方法

总结:SingleRequestonSizeReady方法的调用会根据View的宽高,如果设置为wrapContent,则onSizeReady的调用会推迟到viewTree绘制之前,否则就会立即执行。归根结底都会执行SingleRequestonSizeReady

接着往下走,看onSizeReady方法

com.bumptech.glide.request.SingleRequest.java

public void onSizeReady(int width, int height) {
  synchronized (requestLock) {
  	//修改状态
    status = Status.RUNNING;
	//获取剪裁乘数因子并据此修改宽高值
    float sizeMultiplier = requestOptions.getSizeMultiplier();
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
	//加载数据
    loadStatus =
        engine.load(
            glideContext,
            model,
            requestOptions.getSignature(),
            this.width,
            this.height,
            requestOptions.getResourceClass(),
            transcodeClass,
            priority,
            requestOptions.getDiskCacheStrategy(),
            requestOptions.getTransformations(),
            requestOptions.isTransformationRequired(),
            requestOptions.isScaleOnlyOrNoTransform(),
            requestOptions.getOptions(),
            requestOptions.isMemoryCacheable(),
            requestOptions.getUseUnlimitedSourceGeneratorsPool(),
            requestOptions.getUseAnimationPool(),
            requestOptions.getOnlyRetrieveFromCache(),
            this,
            callbackExecutor);
  }
}

代码中注释写的很清楚,接着往下看

com.bumptech.glide.load.engine.Engine.java
>代码片段23

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,
    Executor callbackExecutor) {
	//创建EngineKey,这个key是用来在内存中缓存Engine
  EngineKey key =
      keyFactory.buildKey(
          model,
          signature,
          width,
          height,
          transformations,
          resourceClass,
          transcodeClass,
          options);

  EngineResource<?> memoryResource;
  synchronized (this) {
  //优先从内存加载图片 根据key寻找资源 这里的资源缓存在一个Map中value是EngineResource的弱引用
    memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);

    if (memoryResource == null) {
      return waitForExistingOrStartNewJob(
          glideContext,
          model,
          signature,
          width,
          height,
          resourceClass,
          transcodeClass,
          priority,
          diskCacheStrategy,
          transformations,
          isTransformationRequired,
          isScaleOnlyOrNoTransform,
          options,
          isMemoryCacheable,
          useUnlimitedSourceExecutorPool,
          useAnimationPool,
          onlyRetrieveFromCache,
          cb,
          callbackExecutor,
          key,
          startTime);
    }
  }
  //从内存中加载出资源了,执行回调
  cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
  return null;
}

先来看一下loadFromMemory是如何从内存加载图片的

private EngineResource<?> loadFromMemory(EngineKey key, boolean isMemoryCacheable, long startTime) {
	//如果禁止内存缓存就直接返回
  if (!isMemoryCacheable) {
    return null;
  }
  //首先从ActiveResources中获取
  EngineResource<?> active = loadFromActiveResources(key);
  if (active != null) {
    return active;
  }
  //从LruResourceCache中取,还记得前面讲new Glide那端代码吗?
  //LruResourceCache这个对象就是在那里生成的
  EngineResource<?> cached = loadFromCache(key);
  if (cached != null) {
    return cached;
  }
  return null;
}

//下面这三个方法是获取内存缓存的相关代码
@Nullable
private EngineResource<?> loadFromActiveResources(Key key) {
  EngineResource<?> active = activeResources.get(key);
  if (active != null) {
    active.acquire();
  }

  return active;
}

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

private EngineResource<?> getEngineResourceFromCache(Key key) {
//cache 默认是LruResourceCache对象,是创建Engine对象时候作为参数传进来的,LruResourceCache继承自LruCache类
  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, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ true, key, /*listener=*/ this);
  }
  return result;
}

说一下这两种缓存方式,第一种ActiveResources是通过HashMap存储的是资源的弱引用,而第二中默认情况下是通过LruCache类中的cache对象(LinkedHashMap类型的数据结构)存储资源的,此cache初始容量100,负载因子0.75,采用的是LRU算法。这两种缓存方式都是内存缓存,面试的时候经常问到,这一点需要注意。

从内存加载图片的时候,先从activeResources这里面去取数据,如果取到了直接返回,取不到就从cache中去取数据,如果取到了,就将资源在activeResources里面存一份,并返回。存的时候是先创建一个弱引用ResourceWeakReference类型的对象,这里有一点需要说明,创建弱引用对象的时候,会判断isMemoryCacheableisActiveResourceRetentionAllowed的值,都为true的话,就会存资源,否则存一个null。这两个值,前者是使用glide的时候通过skipMemoryCache方法设置,表示是跳过内存缓存,后者可以通过在自定义的AppGlideModule类的applyOptions方法中,通过调用builder.setIsActiveResourceRetentionAllowed(true);来设置。将这个变量设置为true有可能会暂时增加应用程序的内存使用量。

回到代码片段23,如果内存缓存没找到资源就接着调用waitForExistingOrStartNewJob方法并返回。

com.bumptech.glide.load.engine.Engine.java

private <R> LoadStatus waitForExistingOrStartNewJob(
    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,
    Executor callbackExecutor,
    EngineKey key,
    long startTime) {
	//注释7
  EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
  if (current != null) {
    current.addCallback(cb, callbackExecutor);
    return new LoadStatus(cb, current);
  }
  //负责通过添加和删除回调来管理一次加载过程,并且在加载完成的时候负责通知回调。实现了DecodeJob.Callback
  EngineJob<R> engineJob =
      engineJobFactory.build(
          key,
          isMemoryCacheable,
          useUnlimitedSourceExecutorPool,
          useAnimationPool,
          onlyRetrieveFromCache);
  //负责从缓存资源或者远程源文件中解码并转码的类,他实现了Runnable接口
  DecodeJob<R> decodeJob =
      decodeJobFactory.build(
          glideContext,
          model,
          key,
          signature,
          width,
          height,
          resourceClass,
          transcodeClass,
          priority,
          diskCacheStrategy,
          transformations,
          isTransformationRequired,
          isScaleOnlyOrNoTransform,
          onlyRetrieveFromCache,
          options,
          engineJob);

  jobs.put(key, engineJob);
  engineJob.addCallback(cb, callbackExecutor);
  engineJob.start(decodeJob);
  return new LoadStatus(cb, engineJob);
}

注释7中就是从Jobs中根据key查找缓存的engineJob对象,至于Jobs类就是管理engineJob缓存的,它内部维护着两个hashmap来存储engineJob,至于用哪个map存,是根据开发者设置的onlyRetrieveFromCachetruefalse来决定的,这里笔者有点疑惑,感觉这两个map没区别,读者有想法的可以留言,解答笔者的疑惑。若果从缓存中获取到了engineJob,就证明相同的请求工作已经存在了,所以不在需要了。执行if中的addCallback逻辑。addCallback代码如下,可以简单看一下

> 代码片段24
//参数说明 cb==就是SingleRequest对象,callbackExecutor就是调用into方法时创建Executors.mainThreadExecutor()、是主线程池
synchronized void addCallback(final ResourceCallback cb, Executor callbackExecutor) {
  //注释8  这里注意下,后面会用到
  //这里cbs是ResourceCallbacksAndExecutors类型,他的add方法会在他的成员变量
  //List<ResourceCallbackAndExecutor> callbacksAndExecutors中,把add方法的两个参数
  //封装成一个对象ResourceCallbackAndExecutor并添加进列表中。ResourceCallbackAndExecutor这个对象的cb变量就是参数cb,executor变量就是callbackExecutor参数
  //这里的参数cb就是SingleRequest
  //参数callbackExecutor 就是我们调用into方法中,系统帮我们创建的Executors.mainThreadExecutor() 他通过handler将子线程中的代码发往主线程执行
  cbs.add(cb, callbackExecutor);
  if (hasResource) {
    // Acquire early so that the resource isn't recycled while the Runnable below is still sitting
    // in the executors queue.
    incrementPendingCallbacks(1);
    //有资源、直接回调成功
    callbackExecutor.execute(new CallResourceReady(cb));
  } else if (hasLoadFailed) {
    incrementPendingCallbacks(1);
    //没有资源,调用失败
    callbackExecutor.execute(new CallLoadFailed(cb));
  } else {
    Preconditions.checkArgument(!isCancelled, "Cannot add callbacks to a cancelled EngineJob");
  }
}

接着看注释7处,如果没有从缓存中取到engineJob,就会创建一个,然后执行后面的engineJob.start(decodeJob);代码

com.bumptech.glide.load.engine.EngineJob.java

public synchronized void start(DecodeJob<R> decodeJob) {
  this.decodeJob = decodeJob;
  GlideExecutor executor =
      decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
      //到这里之前一直都在主线程,下面这句代码就会切换到子线程
  executor.execute(decodeJob);
}

com.bumptech.glide.load.engine.DecodeJob.java

boolean willDecodeFromCache() {
  Stage firstStage = getNextStage(Stage.INITIALIZE);
  return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
}

//这个方法后面还会出现。根据
//Stage表示从哪里解码数据,或者当前解码阶段 。枚举类型,取值分别为
//1、INITIALIZE 初始化阶段
//2、RESOURCE_CACHE 从缓存的资源解码
//3、DATA_CACHE  从缓存的源数据解码。
//4、SOURCE 从网络加载
//5、ENCODE 加载成功后的编码阶段
//6、FINISHED 结束
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);
  }
}

上面方法先获取executor对象,根据是否使用磁盘缓存来决定使用哪个executor。看下上面getNextStage方法,根据传进来的参数Stage=INITIALIZE,进入第一个case,成员变量diskCacheStrategy就是使用Glide的时候设置的缓存策略,如果没传就用默认的AUTOMATIC策略。而他的decodeCachedResource方法默认返回true,所以getNextStage方法返回的是Stage.RESOURCE_CACHE,进而willDecodeFromCache方法返回的是true,所以获取到的executor对象就是diskCacheExecutor。这里diskCacheExecutor就是代码片段4中build方法里的第二个if判断中的变量,是一个GlideExecutor对象,他内部代理的线程池是核心线程数和最大线程数都为1的ThreadPoolExecutor对象,接着调用executor.execute(decodeJob);代码,而且我们那知道decodeJob实现了Runnable接口,好了看下execute方法

@Override
public void execute(@NonNull Runnable command) {
	//
  delegate.execute(command);
}

这不就是一个线程池执行线程的过程嘛~,然后线程执行,就会在子线程执行decodeJobrun方法,所以接下来进入子线程看看run方法怎么执行的。但是在看run方法之前,我们先看一下前面一个遗留的方法,前面创建Glide对象的时候,我说过最终会走Glide的构造方法,这个构造方法有一百多行,现在我们贴出部分代码

Glide(@NonNull Context context,@NonNull Engine engine,@NonNull MemoryCache memoryCache,@NonNull BitmapPool bitmapPool,@NonNull ArrayPool arrayPool,
@NonNull RequestManagerRetriever requestManagerRetriever,@NonNull ConnectivityMonitorFactory connectivityMonitorFactory,int logLevel,
@NonNull RequestOptionsFactory defaultRequestOptionsFactory,@NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
@NonNull List<RequestListener<Object>> defaultRequestListeners,boolean isLoggingRequestOriginsEnabled,boolean isImageDecoderEnabledForBitmaps) {
    //设置参数中传进来的成员变量     此处略....
	//管理组件注册以扩展或替换Glide的默认加载,解码和编码逻辑,后面对调用大量的append方法
    registry = new Registry();
    registry.register(new DefaultImageHeaderParser());
    ///略。。。
	
    registry
        .append(int.class, InputStream.class, resourceLoaderStreamFactory)
        .append(int.class, ParcelFileDescriptor.class, resourceLoaderFileDescriptorFactory)
        .append(Integer.class, InputStream.class, resourceLoaderStreamFactory)
        .append(Integer.class, ParcelFileDescriptor.class, resourceLoaderFileDescriptorFactory)
        .append(Integer.class, Uri.class, resourceLoaderUriFactory)
        .append(int.class, AssetFileDescriptor.class, resourceLoaderAssetFileDescriptorFactory)
        .append(Integer.class, AssetFileDescriptor.class, resourceLoaderAssetFileDescriptorFactory)
        .append(int.class, Uri.class, resourceLoaderUriFactory)
        .append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>())
        .append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>())
        .append(String.class, InputStream.class, new StringLoader.StreamFactory())
        .append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
        .append(
            String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory())
        
        .append(Drawable.class, Drawable.class, new UnitDrawableDecoder())
        /* 注册资源转码器 资源转码器可以从给定的资源类型(第一个参数)转换为给定的转码类型(第二个参数)。*/
        .register(Bitmap.class, BitmapDrawable.class, new BitmapDrawableTranscoder(resources))
		//略其他资源转码器
    ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
    
    glideContext = new GlideContext(context,arrayPool,registry,imageViewTargetFactory,
            		defaultRequestOptionsFactory,defaultTransitionOptions,defaultRequestListeners,
            		engine,isLoggingRequestOriginsEnabled,logLevel);
}

看其中一个append方法append(String.class, InputStream.class, new StringLoader.StreamFactory())append方法三个参数,第一个表示数据源的类类型,第二个表示加载之后的数据的类类型,第三个表示ModelLoader的工厂类,而ModelLoader<Model,Data>就是其实就是将数据源(例如url,file)解析成图片数据(例如数据流)的管理接口。针对不同的数据源转换成不同的图片数据,有具体的类,他们都实现了ModelLoader接口。上面构造方法中也看到了,有各种不同的Modeldata类型的转换。而append方法会将三个参数封装到一个Entry<Model,Data>对象中,然后缓存到MultiModelLoaderFactory对象的一个entrylist中。
好了,本篇文章先讲到这里,本篇文章中我们讲到了Glide的三级缓存中的第一级内存缓存,本篇文章中的代码也都是运行在主线程,下一篇文章我们就将进入子线程看看数据真正的加载逻辑以及加载完成后的缓存和显示逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值