Glide4.8源码拆解(二)核心加载流程

栏目: 数据库 · 发布时间: 5年前

内容简介:在上一篇文章中介绍了Glide基本的调用流程,总结起来就是本章要讨论的内容:在讨论Engine之前,还是从调用它的地方开始

在上一篇文章中介绍了Glide基本的调用流程,总结起来就是 Engine 是真正加载资源的入口, SingleRequest 起到连接 RequestManagerTargetEngine 的纽带关系,本文将承接上文,探讨Glide的加载流程。

本章要讨论的内容:

  • Engine的工作流程;
  • 内存缓存ActiveResource原理剖析;
  • 内存缓存MemoryCache原理剖析;
  • EngineJob缓存分析;
  • EngineJob和DecodeJob的工作原理;

在讨论Engine之前,还是从调用它的地方开始 SingleReques.onSizeReady

从Engine开始

SingleRequest.java

@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));
    }
    //创建Engine对象
    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是回调接口

    // have completed asynchronously.
    if (status != Status.RUNNING) {
      loadStatus = null;
    }
    if (IS_VERBOSE_LOGGABLE) {
      logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
  }
  
复制代码

Engine.load()方法有很多参数,其中大部分是从requestOptions中获得,值得注意的是最后一个参数 ResourceCallback ,,由于Engine的缓存加载逻辑是异步的,所以SingleRequest得到Engine的结果就全在实现方法 onResourceReady()onLoadFailed() 里了;SingleRequest的回调不再讲解,我们要往底层探索,从Engine这个类开始;注意,Engine.load()的调用还在主线程中;

Engine的初始化和加载流程

Engine.java

public class Engine implements EngineJobListener,
    MemoryCache.ResourceRemovedListener,
    EngineResource.ResourceListener {
    
    private final Jobs jobs;
    private final MemoryCache cache;
    private final EngineJobFactory engineJobFactory;
    private final ResourceRecycler resourceRecycler;
    private final LazyDiskCacheProvider diskCacheProvider;
    private final DecodeJobFactory decodeJobFactory;
    private final ActiveResources activeResources;
  
    //构造方法
    Engine(MemoryCache cache,
      DiskCache.Factory diskCacheFactory,
      GlideExecutor diskCacheExecutor,
      GlideExecutor sourceExecutor,
      GlideExecutor sourceUnlimitedExecutor,
      GlideExecutor animationExecutor,
      Jobs jobs,
      EngineKeyFactory keyFactory,
      ActiveResources activeResources,
      EngineJobFactory engineJobFactory,
      DecodeJobFactory decodeJobFactory,
      ResourceRecycler resourceRecycler,
      boolean isActiveResourceRetentionAllowed) {
    this.cache = cache;
    //创建diskCacheProvider
    this.diskCacheProvider = new LazyDiskCacheProvider(diskCacheFactory);
    //创建activeResources
    if (activeResources == null) {
      activeResources = new ActiveResources(isActiveResourceRetentionAllowed);
    }
    this.activeResources = activeResources;
    //监听
    activeResources.setListener(this);
    //创建EngineKeyFactory()
    if (keyFactory == null) {
      keyFactory = new EngineKeyFactory();
    }
    this.keyFactory = keyFactory;
    //创建Jobs
    if (jobs == null) {
      jobs = new Jobs();
    }
    this.jobs = jobs;
    //创建engineJobFactory
    if (engineJobFactory == null) {
      engineJobFactory =
          new EngineJobFactory(
              diskCacheExecutor, sourceExecutor, sourceUnlimitedExecutor, animationExecutor, this);
    }
    this.engineJobFactory = engineJobFactory;
    //创建decodeJobFactory
    if (decodeJobFactory == null) {
      decodeJobFactory = new DecodeJobFactory(diskCacheProvider);
    }
    this.decodeJobFactory = decodeJobFactory;
    //创建resourceRecycler
    if (resourceRecycler == null) {
      resourceRecycler = new ResourceRecycler();
    }
    this.resourceRecycler = resourceRecycler;
    //监听
    cache.setResourceRemovedListener(this);
  }
  
    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);
    //从当前正在使用的Resources里面去
    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);
      }
      //返回null
      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);
      }
       //返回null
      return null;
    }
    //以上都没有命中,试图从已存在的任务中对应的EngineJob
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
        //如果去到,把cb往下传递
      current.addCallback(cb);
      if (VERBOSE_IS_LOGGABLE) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      //返回结果
      return new LoadStatus(cb, current);
    }
    //取不到创建下新的EngineJob
    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);
    //创建新的DecodeJob
    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);
    //将当前的engineJob添加到缓存中
    jobs.put(key, engineJob);
    //回调往下传递
    engineJob.addCallback(cb);
    //engineJob开始执行
    engineJob.start(decodeJob);

    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
  }
}
复制代码

在Engine的构造方法中,创建了默认的各种factory和容器,诸如 engineJobFactorydecodeJobFactoryJobsactiveResources 等,各种参数先不一一介绍,我们看load()方法,这是整个调用的出发点;我在代码中已经注释的很清晰,下面再梳理一遍流程:

load流程

loadFromActiveResources()
loadFromCache()

接下来我们从loadFromActiveResources开始,分析感兴趣的方法

loadFromActiveResources流程

Engine.java

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

ActiveResource的要从activeResources中获取,activeResources在Engine构造方法中创建,我们分析ActiveResource类的简单实现;

ActiveResource.java

final class ActiveResources {

    private static final int MSG_CLEAN_REF = 1;
    
    final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
    private ReferenceQueue<EngineResource<?>> resourceReferenceQueue;
    private Thread cleanReferenceQueueThread;
    
    private ResourceListener listener;//一般engine监听次方法
    //缓存的复用在主线程中执行
    private final Handler mainHandler = new Handler(Looper.getMainLooper(), new Callback() {
    @Override
    public boolean handleMessage(Message msg) {
      if (msg.what == MSG_CLEAN_REF) {
        cleanupActiveReference((ResourceWeakReference) msg.obj);
        return true;
      }
      return false;
    }
  });
  
    //设置监听
    void setListener(ResourceListener listener) {
    this.listener = listener;
    }
    
    //get方法
    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;
  }
  
  //activate方法,相当于put
  void activate(Key key, EngineResource<?> resource) {
    ResourceWeakReference toPut =
        new ResourceWeakReference(
            key,
            resource,
            getReferenceQueue(),
            isActiveResourceRetentionAllowed);

    ResourceWeakReference removed = activeEngineResources.put(key, toPut);
    if (removed != null) {
      removed.reset();//移除的弱引用对象需要清除强引用
    }
  }
  
  //清除当前被GC的ref对象
  void cleanupActiveReference(@NonNull ResourceWeakReference ref) {
    Util.assertMainThread();
    activeEngineResources.remove(ref.key);//从集合中移除掉

    if (!ref.isCacheable || ref.resource == null) {
      return;
    }
    //创建新的对象EngineResource,复用ref.resource,
    EngineResource<?> newResource =
        new EngineResource<>(ref.resource, /*isCacheable=*/ true, /*isRecyclable=*/ false);
    newResource.setResourceListener(ref.key, listener);
    listener.onResourceReleased(ref.key, newResource);
  }
  
    //创建resourceReferenceQueue,用来监听垃圾回收对象
    if (resourceReferenceQueue == null) {
      resourceReferenceQueue = new ReferenceQueue<>();
      //创建线程监听弱引用回收对列
      cleanReferenceQueueThread = new Thread(new Runnable() {
        @SuppressWarnings("InfiniteLoopStatement")
        @Override
        public void run() {
          //设置线程优先级有后台线程
          Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
          cleanReferenceQueue();
        }
      }, "glide-active-resources");
      cleanReferenceQueueThread.start();
    }
    return resourceReferenceQueue;
  }
  //shutdown中断线程,清除队列
  void shutdown() {
    isShutdown = true;
    if (cleanReferenceQueueThread == null) {
      return;
    }

    cleanReferenceQueueThread.interrupt();
    try {
      cleanReferenceQueueThread.join(TimeUnit.SECONDS.toMillis(5));
      if (cleanReferenceQueueThread.isAlive()) {
        throw new RuntimeException("Failed to join in time");
      }
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
    }
  }

  //清除回收对象
@Synthetic void cleanReferenceQueue() {
    while (!isShutdown) {
      try {
        ResourceWeakReference ref = (ResourceWeakReference) resourceReferenceQueue.remove();
        mainHandler.obtainMessage(MSG_CLEAN_REF, ref).sendToTarget();

        // This section for testing only.
        DequeuedResourceCallback current = cb;
        if (current != null) {
          current.onResourceDequeued();
        }
        // End for testing only.
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
      }
    }
  }
  //弱引用监听对象,强引用保存真正的资源
  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);
      //保存key
      this.key = Preconditions.checkNotNull(key);
      //保存resource,强引用
      this.resource =
          referent.isCacheable() && isActiveResourceRetentionAllowed
              ? Preconditions.checkNotNull(referent.getResource()) : null;
      isCacheable = referent.isCacheable();
    }

    //清除强引用
    void reset() {
      resource = null;
      clear();
    }
  }
    
}
复制代码

ActiveResource缓存原理

ActiveResources采用HashMap+WeakRefence方式保存EngineResource对象,没有对集合size做限制,在使用WeakReference的时候,创建了一个ReferenceQueue,来记录被GC回收的EngineResource对象,而且在创建ReferenceQueue时生成了一个后台线程cleanReferenceQueueThread,不断地执行 cleanReferenceQueue() 方法,一旦ReferenceQueue取出不为空,便取出ref对象,执行 cleanupActiveReference() 方法

有必要看一下EngineResource类结构:

EngineResource.java

class EngineResource<Z> implements Resource<Z> {
  private final boolean isCacheable;
  private final boolean isRecyclable;
  private ResourceListener listener;
  private Key key;
  private int acquired;
  private boolean isRecycled;
  private final Resource<Z> resource;//真正的resource

  interface ResourceListener {
    void onResourceReleased(Key key, EngineResource<?> resource);
  }

  EngineResource(Resource<Z> toWrap, boolean isCacheable, boolean isRecyclable) {
    resource = Preconditions.checkNotNull(toWrap);
    this.isCacheable = isCacheable;
    this.isRecyclable = isRecyclable;
  }

  void setResourceListener(Key key, ResourceListener listener) {
    this.key = key;
    this.listener = listener;
  }

  Resource<Z> getResource() {
    return resource;
  }
}
复制代码

本质上EngineResource是对Resource的包装类,所以下面的gc分析一定要区分 EngineResourceResource ,这俩不是一个对象;

牛掰的弱引用复用机制

ResourceWeakReference这个类不简单,它本意是对EngineResource的弱引用,其实在构造它时候,会把EngineResource.resource和EngineResource.key以强引用的形式保存,所以垃圾回收的是EngineResource,却回收不掉EngineResource.resource,因为此时resource会被ResourceWeakReference引用;

cleanupActiveReference() 首先取出ref.resource,这个对象是强引用,不会被回收,被回收的是ref包装的EngineResource;然后创建新的EngineResource包装真正的resource,最终调用资源回收的监听 listener.onResourceReleased(ref.key, newResource) ,而 setListener()Engine 构造方法中调用;看一下Engine.onResourceReleased()方法的实现:

Engine.java

public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
    Util.assertMainThread();
    //把key对应的ResourceWeakReference从Map中移除
    activeResources.deactivate(cacheKey);
    if (resource.isCacheable()) {
        //内存缓存复用
      cache.put(cacheKey, resource);
    } else {
      resourceRecycler.recycle(resource);
    }
  }
复制代码

Engine在 onResourceReleased 时,重新保存了EngineResource对象,并且在此之前,还调用了activeResources.deactivate(cacheKey);

为什么要deactivate,下面解释一下原因:

因为在 ActiveResources.cleanupActiveReference() 中创建新的EngineResource来包装被回收的EngineResource下面的resource,但是这个resource还在被ref强引用,所以执行 activeResources.deactivate(cacheKey) 会清除ref多resource的强引用;

弄明白了这些,ActiveResources原理基本上搞明白了;

小结:

ActiveResources 采用弱引用的方式,记录 EngineResource 的回收情况,同时采取强引用保存 EngineResource.resource ,在 ActiveResources 中会有个后台线程会执行清理工作,一旦发现某个 EngineResource 被回收,就会拿出其对应的 resource ,然后创建一个新的 EngineResource 包装这个 resource ,之后回调给 Engine ,让其做内存缓存,最后 Engine 调用 activeResources.deactivate(cacheKey) 解除 refresource 强引用。


以上所述就是小编给大家介绍的《Glide4.8源码拆解(二)核心加载流程》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

HTTPS权威指南

HTTPS权威指南

[英] Ivan Risti? / 杨洋、李振宇、蒋锷、周辉、陈传文 / 人民邮电出版社 / 2016-9 / 99.00元

本书是集理论、协议细节、漏洞分析、部署建议于一体的详尽Web应用安全指南。书中具体内容包括:密码学基础,TLS协议,PKI体系及其安全性,HTTP和浏览器问题,协议漏洞;最新的攻击形式,如BEAST、CRIME、BREACH、Lucky 13等;详尽的部署建议;如何使用OpenSSL生成密钥和确认信息;如何使用Apache httpd、IIS、Nginx等进行安全配置。一起来看看 《HTTPS权威指南》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

在线进制转换器
在线进制转换器

各进制数互转换器

html转js在线工具
html转js在线工具

html转js在线工具