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源码拆解(二)核心加载流程》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Transcending CSS

Transcending CSS

Andy Clarke、Molly E. Holzschlag / New Riders / November 15, 2006 / $49.99

As the Web evolves to incorporate new standards and the latest browsers offer new possibilities for creative design, the art of creating Web sites is also changing. Few Web designers are experienced p......一起来看看 《Transcending CSS》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具