Glide活跃活动缓存

124 阅读1分钟

Glide活跃活动缓存:activeResources:ActiveResources。 活跃缓存他是没有大小限制的,有本事的话你可以无限往里面塞数据。来看下他的类:

final class ActiveResources {
 final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
  private final ReferenceQueue<EngineResource<?>> resourceReferenceQueue = new ReferenceQueue<>();
 }

数据是被保存到activeEngineResources这个HashMap里面。这个map是没容量限制的。我们可以看到他的key是一个key对象,他的键值是一个弱引用。

  static final class ResourceWeakReference extends WeakReference<EngineResource<?>> {

    final Key key;
    final boolean isCacheable;
    Resource<?> resource;

    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.isMemoryCacheable() && isActiveResourceRetentionAllowed
              ? Preconditions.checkNotNull(referent.getResource())
              : null;
      isCacheable = referent.isMemoryCacheable();
    }
  }
}

为什么要用弱引用呢。我们知道弱引用有一个特性。在jvm触发垃圾回收的时候会回收掉弱引用。这也就是为什么glide在活动缓存里面没有设置容量大小限制的原因,因为他很容易就被全部干掉。
现在来看下活动缓存是怎么塞数据的:

//ActiveResouces.java

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

在塞数据的时候,如果存在同名的key,那么就会把上一个键值给重置掉。

这里还需要说一点,Glide监听了gc操作,那他是怎么监听的呢,就是通过弱引用里的ReferenceQueue来监听的:

// ActiveResources.java
void cleanReferenceQueue() {
  while (!isShutdown) {
    try {
      ResourceWeakReference ref = (ResourceWeakReference) resourceReferenceQueue.remove();
      cleanupActiveReference(ref);
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
    }
  }
}

开启了个线程无限循环,用来监听ResourceQueue的移除操作。当触发了gc就会,我们的ResourceQueue.remove就会收到反馈,然后删除了hasmap里面的值,然后如果我们开启了内存缓存,这个时候从活动缓存里面移除的数据会被添加到内存缓存里面。

//ActiveResources.java
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);
}

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

内存缓存的知识后面再讲,现在需要知道的是,活动缓存里面的数据会被添加到内存缓存里面。