Glide源码——Engine活动资源、内存缓存部分

本篇文章涉及EngineKey、EngineResource、ActiveResource、LruResourceCache类。

通过分析SingleRequest的源码我们知道,图片的加载是从Engine.load()开始:

public synchronized <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 = keyFactory.buildKey(model, signature, width, height, transformations,
      resourceClass, transcodeClass, options);
  EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
  if (active != null) {
    cb.onResourceReady(active, DataSource.MEMORY_CACHE);
    return null;
  }
  EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
  if (cached != null) {
    cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
    return null;
  }

先说一下,SingleRequest中的成员变量engine是在Glide初始化的时候生成的实例,然后作为参数不断传递到SingleRequest中。

一、EngineKey

首先生成一个EngineKey,EngineKey实现了Key接口,内部重写了equals()方法,当model、signature、width、height、transformations、resourceClass、transcodeClass、options都相等时才认为是同一个EngineKey。EngineKey的生成用了简单工厂方法,实现在EngineKeyFactory类,该类就一个方法,不知道为何不直接写到EngineKey类里面,非得创建一个类。也可以看到Glide很多地方创建对象都用了简单工厂方法

EngineKey buildKey(Object model, Key signature, int width, int height,
    Map<Class<?>, Transformation<?>> transformations, Class<?> resourceClass, Class<?> transcodeClass, Options options) {
  return new EngineKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options);
}

EngineKey重写了Key的updateDiskCacheKey()方法,不过里面的实现是抛出了异常,这个还没有看懂,TODO

@Override
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
  throw new UnsupportedOperationException();
}

二、EngineResource

实现了Resource<Z>接口,同时有几个成员变量记录状态:isCacheable、isRecyclable、key、isRecycled;

三、ActiveResource

根据EngineKey去查找有没有存在的ActivityResource,如果有则回调onResourceReady(active, DataSource.MEMORY_CACHE),并返回空;

private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
  if (!isMemoryCacheable) {
    return null;
  }
  EngineResource<?> active = activeResources.get(key);
  if (active != null) {
    active.acquire();
  }
  return active;
}

其中activeResource是在Engine初始化的时候创建的,是Glide的第一级缓存,表示当前正在使用的资源,当下一级资源中获取到资源时会加入ActivityResource,当资源不再使用时会移除,因此该缓存中的资源生命周期较短,没有内存大小限制。

ActiveResource是一个管理类,内部有成员变量 Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>(); 以EngineKey为Key保存着活跃资源的弱引用;ResourceWeakReference继承了WeakReference<EngineResource<?>>,且传入了 ReferenceQueue<EngineResource<?>> resourceReferenceQueue 来接收回收信号。同时创建了一个单线程池运行一个Runnable,Runnable中死循环不断监听被回收的资源引用,被回收的资源引用对应的key需要从activeEngineResources中移除,且通知外部listener(其实就是Engine本身)有资源被移除了:

void cleanupActiveReference(@NonNull ResourceWeakReference ref) {
  // Fixes a deadlock where we normally acquire the Engine lock and then the ActiveResources lock
  // but reverse that order in this one particular test. This is definitely a bit of a hack...
  synchronized (listener) {
    synchronized (this) {
      activeEngineResources.remove(ref.key);
      if (!ref.isCacheable || ref.resource == null) {
        return;
      }
      EngineResource<?> newResource = new EngineResource<>(ref.resource, /*isCacheable=*/ true, /*isRecyclable=*/ false);
      newResource.setResourceListener(ref.key, listener);
      listener.onResourceReleased(ref.key, newResource);
    }
  }
}
@Synthetic void cleanReferenceQueue() {
  while (!isShutdown) {
    try {
      ResourceWeakReference ref = (ResourceWeakReference) resourceReferenceQueue.remove(); //死循环接收要回收的资源引用;
      cleanupActiveReference(ref);
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
    }
  }
}

四、LruResourceCache

当在ActiveResource中没有找到key对应的资源时,就会去engine的cache中找,cache是LruResourceCache的实例。LruResourceCache继承自LruCache,用到了近期最少使用算法,这个后面单独写一篇来讲。

在cache中找到Key对应的资源则回调onResourceReady(active, DataSource.MEMORY_CACHE),并返回空;同时需要将该资源加入ActiveResource,因为这个资源即将被使用。

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对应的旧资源引用需要清除之;
  }
}

如果资源在ActiveResource、LruResourceCache中都没有找到,那么就需要去获取,Glide维护了一个EngineJob类来负责获取资源。

接下来就需要另写一篇文章来分析EngineJob了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值