Glide4.9图片框架源码(三)之into方法后续读取内存缓存

上一节我们解析了为什么Glide能监听页面的生命周期而保证及时回收请求和其他资源,有需要的话看下上一节:

Glide源码之如何绑定Activity的生命周期

上节我们讲到了Glide.with(this).load(url).into(imageView)前面两个方法,这一节我们看下最重要的一环into方法,下面先看下into方法的代码:

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

    BaseRequestOptions requestOptions = this;
    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,
        Executors.mainThreadExecutor());
  }

我们看到into方法的返回值是一个ViewTarget,ViewTarget是对imageview的一个封装,我们后面会讲到,这里第一二行则是判断是否在主线程和做的一个非空判断,我们看后面的代码,这里的if语句主要是对ScaleType进行设置,获取到requestOptions并且设置ScaleType,我们看下下面的return语句的into方法,第三个字段看得出来传入了一个线程池,是不是觉得图片请求快开始了呢,我们先看下glideContext.buildImageViewTarget方法:

public  ViewTarget buildImageViewTarget(
      @NonNull ImageView imageView, @NonNull Class transcodeClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
  }

  public  ViewTarget buildTarget(@NonNull ImageView view,
      @NonNull Class clazz) {
    if (Bitmap.class.equals(clazz)) {
      return (ViewTarget) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
      return (ViewTarget) new DrawableImageViewTarget(view);
    } else {
      throw new IllegalArgumentException(
          "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
  }

这里可以看出,我们将imageView传入imageViewTargetFactory的build方法中,而这是一个工厂方法,针对不同的加载类型生成不同的target,target这里已经与imageView同在,我们返回看下刚才的into方法:

 private > Y into(@NonNull Y target,
      @Nullable RequestListener targetListener,
      BaseRequestOptions options, Executor callbackExecutor) {
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }
    Request request = buildRequest(target, targetListener, options, callbackExecutor);
    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      request.recycle();
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        previous.begin();
      }
      return target;
    }
    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
  }

我们直接看buildRequest方法,看命名方式可以猜出,这里应该是创建一个请求了,这里的代码比较长,我做了一个简化:

  private Request buildRequest(
      Target target,
      @Nullable RequestListener targetListener,
      BaseRequestOptions requestOptions,
      Executor callbackExecutor) {
    return buildRequestRecursive(
        target,
        targetListener,
        /*parentCoordinator=*/ null,
        transitionOptions,
        requestOptions.getPriority(),
        requestOptions.getOverrideWidth(),
        requestOptions.getOverrideHeight(),
        requestOptions,
        callbackExecutor);
  }
  private Request buildRequestRecursive(
      Target target,
      @Nullable RequestListener targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      BaseRequestOptions requestOptions,
      Executor callbackExecutor) {
      .......
    Request mainRequest =
        buildThumbnailRequestRecursive(
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions,
            callbackExecutor);

    if (errorRequestCoordinator == null) {
      return mainRequest;
    }
    .......
    .......
  }
    .......
    .......
  private Request obtainRequest(
      Target target,
      RequestListener targetListener,
      BaseRequestOptions requestOptions,
      RequestCoordinator requestCoordinator,
      TransitionOptions transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      Executor callbackExecutor) {
    return SingleRequest.obtain(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory(),
        callbackExecutor);
  }

  private synchronized void init(
      Context context,
      GlideContext glideContext,
      Object model,
      Class transcodeClass,
      BaseRequestOptions requestOptions,
      int overrideWidth,
      int overrideHeight,
      Priority priority,
      Target target,
      RequestListener targetListener,
      @Nullable List> requestListeners,
      RequestCoordinator requestCoordinator,
      Engine engine,
      TransitionFactory animationFactory,
      Executor callbackExecutor) {
    this.context = context;
    this.glideContext = glideContext;
    this.model = model;
    this.transcodeClass = transcodeClass;
    this.requestOptions = requestOptions;
    this.overrideWidth = overrideWidth;
    this.overrideHeight = overrideHeight;
    this.priority = priority;
    this.target = target;
    this.targetListener = targetListener;
    this.requestListeners = requestListeners;
    this.requestCoordinator = requestCoordinator;
    this.engine = engine;
    this.animationFactory = animationFactory;
    this.callbackExecutor = callbackExecutor;
    status = Status.PENDING;

    if (requestOrigin == null && glideContext.isLoggingRequestOriginsEnabled()) {
      requestOrigin = new RuntimeException("Glide request origin trace");
    }
  }

前面的省略号表示不重要的信息,最终调用到的是init的方法,这里为请求request初始化了很多参数,例如我们前面设置过的model,就是请求的URL,还有是否重新设定了加载的宽高,优先级,动画等等设置,这里就是对请求request的初始化,我们回到最初的into方法:

 private > Y into(@NonNull Y target,
      @Nullable RequestListener targetListener,
      BaseRequestOptions options, Executor callbackExecutor) {
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }
    Request request = buildRequest(target, targetListener, options, callbackExecutor);
    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      request.recycle();
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        previous.begin();
      }
      return target;
    }
    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
  }

buildRequest下面一行,通过target获取了一个previous 的request,随后调用了requestManager.clear(target),这里是保证每次请求都是最新的参数和设置,清除上一个请求。这里的 target.setRequest(request);我们点进去发现调用的是setTag方法,将view和request绑定。最后调用了requestManager.track(target, request),还记得前面我们为什么说RequestManager管理target和request么,我们进track方法看下代码:

  synchronized void track(@NonNull Target target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }

这里还使用的是同步方法,这里持有了两个追踪器,一个是target,一个是request,进track方法看里面的内容:

  private final Set> targets =
      Collections.newSetFromMap(new WeakHashMap, Boolean>());

  public void track(@NonNull Target target) {
    targets.add(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维护了一个set集合,用于存储和管理所有的target对象,下面的几个方法,也正是同步于fragment的和requestmanager的生命周期方法,便于在出发生命周期时对所有的target对象执行操作。我们再来看下requestTracker的runRequest方法,看方法命名是不是猜到快要执行网络请求了呢,来看下代码:

private final Set requests =
      Collections.newSetFromMap(new WeakHashMap());
  @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
  private final List pendingRequests = new ArrayList<>();
  private boolean isPaused;

public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }

requestTracker同样维护了一个requests Set集合管理所有请求。isPaused参数表示如果暂停,那么当前的request添加到一个等待集合中延迟执行,否则直接执行begin方法,我们继续看下begin方法:

  @Override
  public void begin() {
    synchronized (requestLock) {
      assertNotCallingCallbacks();
      stateVerifier.throwIfRecycled();
      startTime = LogTime.getLogTime();
      if (model == null) {
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
          width = overrideWidth;
          height = overrideHeight;
        }
        int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
        onLoadFailed(new GlideException("Received null model"), logLevel);
        return;
      }
      if (status == Status.RUNNING) {
        throw new IllegalArgumentException("Cannot restart a running request");
      }
      if (status == Status.COMPLETE) {
        onResourceReady(resource, DataSource.MEMORY_CACHE);
        return;
      }
      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));
      }
    }
  }

这里调用的是SingleRequest的begin方法,前面是对当前request运行状态的判断,status = Status.WAITING_FOR_SIZE这里直接赋值,表示当前需要等待获取到view的宽高才能进行下一步,如果你在前面的设置中设置过override方法传递了新的宽高,那么这里直接使用你传入的宽高,否则调用target.getSize(this)方法去获取图片所加载的view的宽高,我们跟进去看这个getsize方法:

 void getSize(@NonNull SizeReadyCallback cb) {
      int currentWidth = getTargetWidth();
      int currentHeight = getTargetHeight();
      if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
        cb.onSizeReady(currentWidth, currentHeight);
        return;
      }
      if (!cbs.contains(cb)) {
        cbs.add(cb);
      }
      if (layoutListener == null) {
        ViewTreeObserver observer = view.getViewTreeObserver();
        layoutListener = new SizeDeterminerLayoutListener(this);
        observer.addOnPreDrawListener(layoutListener);
      }
    }

我们发现走到了ViewTarget的getSize方法,ViewTarget正是当初我们封装imageview的target对象,这里直接去获取getTargetWidth、Height,我们不进去看了,就是拿到我们之前传递的image view,获取他的宽高。这里的isViewStateAndSizeValid方法则是判断获取的宽高是否大于0 并且真实可用,可用就表示当前的image view其实已经绘制完成,我们获取的到它的宽高并且直接返回。如果不可用,那么就给image view添加一个绘制的监听addOnPreDrawListener,当绘制完成时我们再去获取它的宽高并且返回。

我们再回到前面的target.getSize方法,继续看下去,宽高获取完成后,调用的是onSizeReady,那么我们跟进去看下:

public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    synchronized (requestLock) {
      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,
              callbackExecutor);

      if (status != Status.RUNNING) {
        loadStatus = null;
      }
      if (IS_VERBOSE_LOGGABLE) {
        logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
      }
    }
  }

这里的status 直接赋值为RUNNING状态了,下面一行的sizeMultiplier变量,还记得我们第一节的Glide的常规使用吗,它作用域缩略图,表示我们想将原图缩放几倍大小,这里是获取设置并且计算新的缩略图宽高,我们不去细究,看下面的重点,engine.load方法。可以看出,这个方法传递了很多参数和设置,包括参数设置广泛的requestOptions,这里应该即将开始加载请求的信息了,我们继续看下去:

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

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

    EngineResource memoryResource;
    synchronized (this) {
      memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);

      if (memoryResource == null) {
        return waitForExistingOrStartNewJob(
            glideContext,
            model,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            options,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache,
            cb,
            callbackExecutor,
            key,
            startTime);
      }
    }
    cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
    return null;
  }

重点来了,看第一行的 keyFactory.buildKey方法,返回值是一个EngineKey,这个key就是我们用于缓存的key,再看看入参的几个字段。model,signature,width,height,options等。由此可见,影响一张缓存的图片,不只是他的url,还包括了要加载的图片宽高、签名和设置等,所以当同一个图片的URL,如果我们加载不同的宽高,那么这个URL是会缓存两次的。

我们继续看有一个memoryResource对象,并且调用了loadFromMemory方法,我们跟进去看一下:

  private EngineResource loadFromMemory(
      EngineKey key, boolean isMemoryCacheable, long startTime) {
    if (!isMemoryCacheable) {
      return null;
    }
    EngineResource active = loadFromActiveResources(key);
    if (active != null) {
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return active;
    }

    EngineResource cached = loadFromCache(key);
    if (cached != null) {
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return cached;
    }
    return null;
  }

第一行我们看到了一个isMemoryCacheable,这个就是我们设置的skipMemoryCache,如果没有设置,那么默认就是可用的,这里如果设置了跳过内存缓存,那么直接执行return语句。继续看这里有两个loadFrom方法,一个是loadFromActiveResources,另一个是loadFromCache,那么两个有什么区别呢?其实两个都是作为内存缓存存在的,一个内部维护的是LURCACHE,另一个则是hashmap ,key就是我们传入的EngineKey,Value则是我们Resource的一个弱引用,我们先看下loadFromActiveResources方法:

 @Nullable
  private EngineResource loadFromActiveResources(Key key) {
    EngineResource active = activeResources.get(key);
    if (active != null) {
      active.acquire();
    }
    return active;
  }

final Map activeEngineResources = new HashMap<>();
  @Nullable
  synchronized 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;
  }

void cleanupActiveReference(@NonNull ResourceWeakReference ref) {
    synchronized (this) {
      activeEngineResources.remove(ref.key);
      if (!ref.isCacheable || ref.resource == null) {
        return;
      }
    }
    EngineResource newResource =
        new EngineResource<>(
            ref.resource, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ false, ref.key, listener);
    listener.onResourceReleased(ref.key, newResource);
  }

 public void onResourceReleased(Key cacheKey, EngineResource resource) {
    activeResources.deactivate(cacheKey);
    if (resource.isMemoryCacheable()) {
      cache.put(cacheKey, resource);
    } else {
      resourceRecycler.recycle(resource, /*forceNextFrame=*/ false);
    }
  }

  synchronized void acquire() {
    if (isRecycled) {
      throw new IllegalStateException("Cannot acquire a recycled resource");
    }
    ++acquired;
  }

loadFromActiveResources方法调用了getkey方法,实际上是从activeEngineResources 的hashmap中去取并返回一个Resource弱引用,通过这个弱引用去拿到真正缓存的Resource,如果缓存为空,则调用cleanupActiveReference方法,第一行activeEngineResources.remove(ref.key)表示,如果弱引用为空表示被回收了,那么这个key也将直接移除。下面判断如果ref.resource没有被回收,那么再根据这个resource 创建一个新的Resource对象并调用onResourceReleased方法。继续看这个方法,可以看出把它放进了cache缓存,这里的cache缓存就是我们上面说的LRUCACHE内存缓存。

继续回到loadFromActiveResources,然后调用acquire方法,看这个方法做了一个++的操作,实际上是对当前缓存做了引用计数+1,当我们每次拿到了缓存,引用计数就加一,如果销毁了,引用计数就减一,当为0的时候,我们的HashMap则会去回收这个缓存。到这里loadFromActiveResources就结束了,下面我们看下loadFromCache方法:

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

  synchronized void activate(Key key, EngineResource resource) {
    ResourceWeakReference toPut =
        new ResourceWeakReference(
            key, resource, resourceReferenceQueue, isActiveResourceRetentionAllowed);

    ResourceWeakReference removed = activeEngineResources.put(key, toPut);
    if (removed != null) {
      removed.reset();
    }
  }

第一行调用了getEngineResourceFromCache,然后直接调用了cache.remove方法,cache是一个MemoryCache接口,实现类是LruResourceCache,这里直接将获取到的缓存移除了,回到loadFromCache方法,如果缓存不为空,同样调用的引用计数方法,然后调用了activeResources.activate(key, cached)方法,这里直接创建了一个弱引用,然后添加到了弱引用的hashmap中。

内存缓存的引用计数是如何运作的?

前面几个章节只是简述了存储和获取内存缓存,没有仔细分析引用计数和什么时候触发,首先我们回到获取内存缓存的位置看看,比较下弱引用缓存和内存缓存的区别在哪:

Engine 类
@Nullable
  private EngineResource loadFromActiveResources(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
      return null;
    }
    EngineResource active = activeResources.get(key);
    if (active != null) {
      active.acquire();
    }
    return active;
  }

这里activeResources.get(key)直接从弱引用缓存中获取,那么我们看这个activeResources是存在与当前的Engine 中的,要知道我们看active.acquire()方法源码:

EngineResource 类
 synchronized void acquire() {
    if (isRecycled) {
      throw new IllegalStateException("Cannot acquire a recycled resource");
    }
    ++acquired;
  }
  void release() {
    synchronized (listener) {
      synchronized (this) {
        if (acquired <= 0) {
          throw new IllegalStateException("Cannot release a recycled or not yet acquired resource");
        }
        if (--acquired == 0) {
          listener.onResourceReleased(key, this);
        }
      }
    }
  }

@Override
  public synchronized void onResourceReleased(Key cacheKey, EngineResource resource) {
    activeResources.deactivate(cacheKey);
    if (resource.isCacheable()) {
      cache.put(cacheKey, resource);
    } else {
      resourceRecycler.recycle(resource);
    }
  }

我们看到这里的acquired做了一次++,表示内存中引用了当前的缓存图片 ,那么相反的,什么时候调用--呢,我们发现只有release方法做了--操作,当acquired=0的时候调用了onResourceReleased方法,我们跟进去看这个是干嘛的。发现当acquired=0的时候,activeResources做了清空key和resource的操作,然后调用cache.put(cacheKey, resource)方法转移存储到了lrucache内存缓存。那么我们看看这个release都在什么时候才回去回收,调用回收的地方很多,其中有这样的一块:

SingleRequest 类
 public synchronized void clear() {
    assertNotCallingCallbacks();
    stateVerifier.throwIfRecycled();
    if (status == Status.CLEARED) {
      return;
    }
    cancel();
    if (resource != null) {
      releaseResource(resource);
    }
    if (canNotifyCleared()) {
      target.onLoadCleared(getPlaceholderDrawable());
    }
    status = Status.CLEARED;
  }

RequestTracker 类
  private boolean clearRemoveAndMaybeRecycle(@Nullable Request request, boolean isSafeToRecycle) {
     if (request == null) {
      return true;
    }
    boolean isOwnedByUs = requests.remove(request);
    isOwnedByUs = pendingRequests.remove(request) || isOwnedByUs;
    if (isOwnedByUs) {
      request.clear();
      if (isSafeToRecycle) {
        request.recycle();
      }
    }
    return isOwnedByUs;
  }

RequestManager 类
  @Override
  public synchronized void onDestroy() {
    targetTracker.onDestroy();
    for (Target target : targetTracker.getAll()) {
      clear(target);
    }
    targetTracker.clear();
    requestTracker.clearRequests();
    lifecycle.removeListener(this);
    lifecycle.removeListener(connectivityMonitor);
    mainHandler.removeCallbacks(addSelfToLifecycle);
    glide.unregisterRequestManager(this);
  }

看到RequestManager的onDestroy方法我想就明白了,引用计数和弱引用缓存activeResource是跟activity绑定在一起的,当activity销毁的时候,那么同时也会回收activeResource的资源并移动到cache内存缓存,此时引用计数为0,当从cache内存缓存中取数据的时候,取完则存储到activeResource缓存,引用计数又++ 。所以这里的引用技术表示当前使用的是activeResource缓存,当activeResource缓存即将被回收的时候,转移到Cache缓存,引用计数--。

总结

看到这里有头绪了吗,为什么要设置两道缓存,为什么获取到的缓存要互相移动,其实以常规的思维,这里只需用LRUCACHE即可,但是这样的设计,避免了频繁去读取LURCACHE并且如果存储的图片资源过多,lrucache也会回收之前的缓存,所以为了避免被回收掉,当我们从lrucache拿到缓存后立马移动到hashmap的弱引用缓存。当然弱引用缓存也有可能被系统回收,所以当弱引用资源还未被回收的时候,再移动到LRUCACHE缓存中,两个缓存互相利用和结合,最大效率的使用了图片资源。到这里我们的内存缓存读取就分析结束了,下一节我们重点分析请求的处理和磁盘缓存。

Glide4.9图片框架源码之获取磁盘缓存和图片请求

你可能感兴趣的:(Glide4.9图片框架源码(三)之into方法后续读取内存缓存)