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

1,603 阅读20分钟

前言

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

本章要讨论的内容:

  • Engine的工作流程;
  • 内存缓存ActiveResource原理剖析;
  • 内存缓存MemoryCache基本原理;
  • 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流程

  1. 通过keyFactory和请求参数,创建EngineKey对象key;
  2. 调用loadFromActiveResources()方法,尝试从活动的Resources中获取active;
  3. 如果步骤2命中,直接回调cb.onResourceReady(),并返回,不命中,执行步骤4;
  4. 调用loadFromCache()方法,尝试从内存缓存中获取cached;
  5. 如果步骤4命中,直接回调cb.onResourceReday(),并返回,不命中,执行步骤6;
  6. 尝试从jobs中获取匹配key的正在执行的EngineJob current;
  7. 如果步骤6命中,把回调添加到current并返回,不命中,执行步骤8;
  8. 通过engineJobFactory创建新的EngineJob对象engineJob;
  9. 根据decodeJobFactory创建新的DecodeJob对象decodeJob;
  10. 把engineJob添加进jobs中,讲回调cb设置到engineJob中;
  11. 执行engineJob.start(decodeJob);

接下来我们从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强引用。

内存缓存第二阶段

loadFromCache()流程分析

Engine.java

private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {//跳出
      return null;
    }

    EngineResource<?> cached = getEngineResourceFromCache(key);
    if (cached != null) {//如果命中
      cached.acquire();//+1操作
      activeResources.activate(key, cached);//添加到activeResource
    }
    return cached;
  }
  
  private EngineResource<?> getEngineResourceFromCache(Key key) {
    Resource<?> cached = cache.remove(key);//从MemoryCache中取
    final EngineResource<?> result;
    if (cached == null) {
      result = null;
    } else if (cached instanceof EngineResource) {
      result = (EngineResource<?>) cached;
    } else {
      //包装
      result = new EngineResource<>(cached, true /*isMemoryCacheable*/, true /*isRecyclable*/);
    }
    return result;
  }

loadFromCache()调用getEngineResourceFromCache()返回cached,如果命中,cached+1,然后把cached存放到activeResources缓存中,getEngineResourceFromCache()主要是调用MemoryCache.remove()返回cached,然后在转成EngineResource返回,主要逻辑还是在MemoryCache中;

LruResourceCache

MemoryCache是一个接口,Engine中使用的cache是在GlideBuilder中创建,默认实现类是LruResourceCache

LruResourceCache.java

public class LruResourceCache extends LruCache<Key, Resource<?>> implements MemoryCache {
  private ResourceRemovedListener listener;
  //构造方法传入最大size
  public LruResourceCache(long size) {
    super(size);
  }
  //设置资源被淘汰的监听
  @Override
  public void setResourceRemovedListener(@NonNull ResourceRemovedListener listener) {
    this.listener = listener;
  }
  //淘汰当前item时调用
  @Override
  protected void onItemEvicted(@NonNull Key key, @Nullable Resource<?> item) {
    if (listener != null && item != null) {
      listener.onResourceRemoved(item);
    }
  }
  //获取当前item的size,字节大小
  @Override
  protected int getSize(@Nullable Resource<?> item) {
    if (item == null) {
      return super.getSize(null);
    } else {
      return item.getSize();
    }
  }
  //内存不足时调用
  @SuppressLint("InlinedApi")
  @Override
  public void trimMemory(int level) {
    if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
      clearMemory();
    } else if (level >= android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
        || level == android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) {
      trimToSize(getMaxSize() / 2);
    }
  }
}

LruResourceCache继承LruCache并实现MemoryCache接口,缓存的真正实现在LruCache中,这个类是Glide自己实现的,同样基于LikeHashMap,没什么特殊点,不过可以看出,item缓存大小的计算放在resource自身,除此之外还有一个setResourceRemovedListener()方法,用来监听资源被淘汰时的回调;

LruResourceCache允许的最大size在构造方法中传入,从GlideBuilder中可以看出是MemorySizeCalculator.getMemoryCacheSize()决定,MemorySizeCalculator有默认的缓存大小计算规则,篇幅有限暂时不讲;

LruResourceCache基本上就是正常的LruCache;保存的是Resource,并不是Bitmap,到现在我们还没有看到Bitmap;

内存缓存小结

上面分析了ActiveResources缓存和MemoryCache缓存,分别使用弱引用技术和LRU技术,构成两级内存缓存,两者有相似之外却又截然不同。

  • 相同之处:都是基于内存做缓存,运行在主线程;
  • 不同之处:ActiveResources依赖垃圾回收机制做淘汰运算,MemoryCache是强引用有最大内存限制,根据最近最少使用规则来淘汰
  • 优先级:ActiveResources优先级高于MemoryCache,ActiveResources当中保存的是活动对象,在ActiveResources某个item被回收时,如果其对应的真正的Resource没有被回收,会下放到MemoryCache当中,当然,从MemoryCache中取出的值,会存放在ActiveResources中;

真正的Job

上面一直再说内存缓存,再回顾一下load流程是:当内存中不存在缓存时,Engine会尝试从jobs中取EngineJob缓存,jobs内部用HashMap保存EngineJob对象,当EngineJob加载完成或者取消时,从将当前job从map中移除,这一级算不上Resource的缓存,只能算是EngineJob的复用,jobs缓存这块就不细说了,下面主要看EngineJob和DecodeJob;

EngineJob.java

public void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }

EngineJob调用start方法执行decodeJob,其中执行decodeJob是异步任务必然会用到线程池,willDecodeFromCache()方法判断是否从cache中获取采取不同的线程池方案;从上述代码不难看出,DecodeJob肯定是Runnable对象,急于分析流程,我们直接进入DecodeJobrun()方法开始:

DecodeJob.java

public void run() {
    GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
    DataFetcher<?> localFetcher = currentFetcher;
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      runWrapped();//run在这里
    } catch (Throwable t) {
      if (stage != Stage.ENCODE) {
        throwables.add(t);
        notifyFailed();
      }
      if (!isCancelled) {
        throw t;
      }
    } finally {
     
      if (localFetcher != null) {
        localFetcher.cleanup();
      }
      GlideTrace.endSection();
    }
  }
  
  //根据stage选择NextGenerator
  private void runWrapped() {
    switch (runReason) {
      case INITIALIZE://初始
        stage = getNextStage(Stage.INITIALIZE);//获取下一个stage
        currentGenerator = getNextGenerator();//获取下一个Generator
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE://从CACHE跳转到SOURCE
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();//DECODE_DATA
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }
  
  //RunReason控制run方法的执行目标
  private enum RunReason {
    INITIALIZE,//第一次执行
    SWITCH_TO_SOURCE_SERVICE,//从CACHE换到SOURCE
    DECODE_DATA,//解析
  }
  

run()方法最终调用runWrapped()runWrapped()根据runReason选择不同的操作,runReason控制run方法执行的目标,上面说过EngineJob代码在线程池中执行,不同的任务有不同的线程池来执行,而这个runReason就是控制当前执行到哪个任务了;

重要:在一次完整的加载流程中,EngineJob的run方法可以被多次调用,每次调用的操作不一样,runReason就是来区分这一状态的:

  1. INITIALIZE 第一次调用run,这次执行的目的是从CACHE中获取缓存
  2. SWITCH_TO_SOURCE_SERVICE 如果从CACHE中获取失败,转成从数据源读取,是第二次调用run
  3. DECODE_DATA 缓存获取成功,对数据进行解析

分阶段读取DiskCache

接下来分析DiskCache,后面出现缓存Cache的字眼,如无特殊标识,都是指DiskCache;

在读取缓存之前,还有两个概念:stageGenerator,在搞清除概念之前,先讲一下Glide的DiskCacheStrategy规则:

  • DiskCacheStrategy.NONE 不进行Disk缓存
  • DiskCacheStrategy.DATA 只缓存原图
  • DiskCacheStrategy.RESOURCE 只缓存多尺寸的图片
  • DiskCacheStrategy.ALL 原图和其他尺寸的图片都缓存
  • DiskCacheStrategy.AUTOMATIC 自动(默认行为)

Glide支持缓存多尺寸图片的,这就加大了读取缓存的复杂程度;

有了这些提升,再来看一下Stage

DecodeJob.java

//Stage表示当前run执行到哪一步骤
  private enum Stage {
    INITIALIZE,//初始状态
    RESOURCE_CACHE,//剪裁图Disk缓存
    DATA_CACHE,//原图Disk缓存
    SOURCE,//远程图片
    ENCODE,//解析状态
    FINISHED,//完成
  }
 
  //获取下一个stage
  private Stage getNextStage(Stage current) {
    switch (current) {
      case INITIALIZE://如果支持多尺寸,下一个state就是RESOURCE_CACHE,否则,从RESOURCE_CACHE开始往下判断
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
      case RESOURCE_CACHE://如果支持原图尺寸,下一个state就是DATA_CACHE,否则,从DATA_CACHE开始往下判断
        return diskCacheStrategy.decodeCachedData()
            ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
      case DATA_CACHE://如果只读缓存,Stage=FINISHED,否则就是SOURCE
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
  }
  //获取state对应的Generator
  private DataFetcherGenerator getNextGenerator() {
    switch (stage) {
      case RESOURCE_CACHE://多尺寸对应的
        return new ResourceCacheGenerator(decodeHelper, this);
      case DATA_CACHE://原图对应的
        return new DataCacheGenerator(decodeHelper, this);
      case SOURCE://远程图片对应的
        return new SourceGenerator(decodeHelper, this);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized stage: " + stage);
    }
  }

stage对应了6种状态,六种状态代表当前加载到哪一阶段:

stage默认进来是INITIALIZE状态,通过调用getNextStage()不断往下推进,Stage的推进就表示缓存的查找顺序;

Stage 阶段解释 DataFetcherGenerator
INITIALIZE 初始状态
RESOURCE_CACHE 多尺寸缓存 ResourceCacheGenerator
DATA_CACHE 原尺寸缓存 DataCacheGenerator
SOURCE 数据源 SourceGenerator
ENCODE 生成resource过程
FINISHED 结束

在获取CACHE阶段,每个Stage对应了一个DataFetcherGenerator,真正触发加载缓存的逻辑在DataFetcherGenerator中,

再回到runWrapped()方法,假设当前stage为INITIALIZE,且用户设置了多尺寸缓存,这样调用getNextStage(Stage.INITIALIZE)时应该得到下一个stage是Stage.RESOURCE_CACHE,从而得到ResourceCacheGenerator对象,剩下就是执行runGenerators()方法:

//根据stage选择NextGenerator
  private void runWrapped() {
    switch (runReason) {
      case INITIALIZE://初始
        stage = getNextStage(Stage.INITIALIZE);//获取下一个stage
        currentGenerator = getNextGenerator();//获取下一个Generator
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE://从CACHE跳转到SOURCE
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();//DECODE_DATA
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }
//循环执行Generators
private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    while (!isCancelled && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {//循环查找缓存过程
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

      if (stage == Stage.SOURCE) {
        reschedule();
        return;
      }
    }
    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
      notifyFailed();
    }
    // onDataFetcherReady.
  }

runGenerators()方法中有一个while循环,推进了stage的前进,循环的主要的判断是currentGenerator.startNext(),而这个startNext()方法又是读取Cache的新开端。

上面说到根据不同的stage创建不同的Generator,我们仅以SourceGenerator来分析;

获取数据:以SourceGenerator为例

SourceGenerator.java

class SourceGenerator implements DataFetcherGenerator,
    DataFetcher.DataCallback<Object>,
    DataFetcherGenerator.FetcherReadyCallback {
   @Override
  public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);//缓存的判断
    }
    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {//有缓存从缓存中获取
      return true;
    }
    sourceCacheGenerator = null;

    loadData = null;//
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);//获取loadData
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);//通过loadData.fetcher获取
      }
    }
    return started;
  }  
  
  //判断是否还有下一个ModelLoader
  private boolean hasNextModelLoader() {
    return loadDataListIndex < helper.getLoadData().size();
  }
  
  private void cacheData(Object dataToCache) {
    long startTime = LogTime.getLogTime();
    try {
      Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
      DataCacheWriter<Object> writer =
          new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
      originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
      helper.getDiskCache().put(originalKey, writer);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Finished encoding source to cache"
            + ", key: " + originalKey
            + ", data: " + dataToCache
            + ", encoder: " + encoder
            + ", duration: " + LogTime.getElapsedMillis(startTime));
      }
    } finally {
      loadData.fetcher.cleanup();
    }

    sourceCacheGenerator =
        new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
  }
}

SourceGenerator实现DataFetcherGenerator接口,主要代码在startNext()方法当中,startNext()最前面会判断数据是否已经在缓存中,缓存存在直接调用cacheData()创建DataCacheGenerator,最终会执行这个GeneratorstartNext()方法,否则,while循环获取loadData,如果满足条件,执行loadData.fetcher.loadData(helper.getPriority(), this);,最后一个参数thisDataFetcher.DataCallback回调接口,获取成功会回调onDataReady(Object data)方法;

SourceGenerator.java

@Override
public void onDataReady(Object data) {
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
    if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      dataToCache = data;
      cb.reschedule();//如果可以缓存,执行cb.reschedule
    } else {
      cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
          loadData.fetcher.getDataSource(), originalKey);//直接回调cb.onDataFetcherReady
    }
  }

onDataReady对数据是否只从缓存做判断,因为当前是获取数据源的数据,如果支持disk缓存,回调cb.reschedule(),否则,回调cb.onDataFetcherReady,那么这个cb是谁? cbFetcherReadyCallback类型,这个cbSourceGenerator构造方法中传入,SourceGenerator是在DecodeJob中创建的,真正是cbDecodeJob,所以代码定位到DecodeJob.onDataFetcherReady()reschedule()方法.

DecodeJob.java

@Override
  public void reschedule() {
    runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;//runReason进行到下一步
    callback.reschedule(this);//callback是EngineJob
  }

  @Override
  public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
      DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;
    this.currentData = data;
    this.currentFetcher = fetcher;
    this.currentDataSource = dataSource;
    this.currentAttemptingKey = attemptedKey;
    if (Thread.currentThread() != currentThread) {
      runReason = RunReason.DECODE_DATA;//runReason进行到下一步
      callback.reschedule(this);//解析数据,
    } else {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        decodeFromRetrievedData();//真正的解析数据,上面的if最终也会走到这里
      } finally {
        GlideTrace.endSection();
      }
    }
  }

reschedule()方法中,首先将runReason推进到SWITCH_TO_SOURCE_SERVICE,然后调用EngineJob.reschedule(this),最终还会再次走到run()方法,不同的是在EngineJob中为decodeJob重新分配了线程池,另一个不同是runReason;

onDataFetcherReady()方法中,会判断当前线程池,如果不符合条件,也会将runReason推进到DECODE_DATA,然后执行EngineJob.reschedule(this),流程和reschedule()回调方法一样,最终会重新走run()方法,run()方法会根据runReason判断逻辑,如果在当前线程池,直接调用decodeFromRetrievedData();

我们上面只分析了onDataFetcherReady()也就是数据成功的情况,失败的情况暂时不讨论了,总结一下SourceGenerator的主要流程:

  1. 通过 helper.getLoadData()获取loadData,调用loadData.fetcher.loadData()来执行load;
  2. DecodeJob接受load回调,如果需要进行cache,回调EngineJob执行cache相关的Generator;
  3. 如果可以解析,调用decodeFromRetrievedData()做解析工作;

提升:onDataFetcherReady()回调的Object不是Bitmap或者File,因为还没到这一步骤,一般是InputStream或者ByteBuffer

解析部分

private void decodeFromRetrievedData() {
   ...
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
   ...
  }
  
  private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data,
      DataSource dataSource) throws GlideException {
     ...
      Resource<R> result = decodeFromFetcher(data, dataSource);//调用decodeFromFetcher
    ...
  }
  
  private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
      throws GlideException {
    LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());//获取loadPath
    return runLoadPath(data, dataSource, path);
  }
  
  private <Data, ResourceType> Resource<R> runLoadPath(Data data, DataSource dataSource,
      LoadPath<Data, ResourceType, R> path) throws GlideException {
    Options options = getOptionsWithHardwareConfig(dataSource);
    DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
    try {
      // ResourceType in DecodeCallback below is required for compilation to work with gradle.
      return path.load(
          rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));//调用path.load
    } finally {
      rewinder.cleanup();
    }
  }

解析方法在DecodeJob中几斤周转,最终从decodeHelper.getLoadPath()得到LoadPath对象,然后调用path.load()执行真正的加载逻辑;

LoadPath.java

public Resource<Transcode> load(DataRewinder<Data> rewinder, @NonNull Options options, int width,
      int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException {
    List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire());
    try {
      return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
    } finally {
      listPool.release(throwables);
    }
  }
  
  private Resource<Transcode> loadWithExceptionList(DataRewinder<Data> rewinder,
      @NonNull Options options,
      int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback,
      List<Throwable> exceptions) throws GlideException {
    Resource<Transcode> result = null;
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = decodePaths.size(); i < size; i++) {
      DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i);
      try {
        result = path.decode(rewinder, width, height, options, decodeCallback);//调用用decodePath.decode
      } catch (GlideException e) {
        exceptions.add(e);
      }
      if (result != null) {
        break;
      }
    }

    if (result == null) {
      throw new GlideException(failureMessage, new ArrayList<>(exceptions));
    }
    return result;
  }

LoadPath中,最终调用loadWithExceptionList()方法,在该方法中,通过循环获取decodePaths中的DecodePath对象,最终判断result是否为空来标志结束,所以代码从LoadPath转到decodePath.decode()方法中;

DecodePath.java

public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
      @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
    Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);//decodeResource流程在这里
    Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);//transformed结果
    return transcoder.transcode(transformed, options);
  }
  
  private Resource<ResourceType> decodeResource(DataRewinder<DataType> rewinder, int width,
      int height, @NonNull Options options) throws GlideException {
    List<Throwable> exceptions = Preconditions.checkNotNull(listPool.acquire());
    try {
      return decodeResourceWithList(rewinder, width, height, options, exceptions);
    } finally {
      listPool.release(exceptions);
    }
  }
  //从list中取出能解析的
private Resource<ResourceType> decodeResourceWithList(DataRewinder<DataType> rewinder, int width,
      int height, @NonNull Options options, List<Throwable> exceptions) throws GlideException {
    Resource<ResourceType> result = null;
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = decoders.size(); i < size; i++) {
      ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
      try {
        DataType data = rewinder.rewindAndGet();
        if (decoder.handles(data, options)) {
          data = rewinder.rewindAndGet();
          result = decoder.decode(data, width, height, options);
        }
      } catch (IOException | RuntimeException | OutOfMemoryError e) {
        exceptions.add(e);
      }

      if (result != null) {
        break;
      }
    }

    if (result == null) {
      throw new GlideException(failureMessage, new ArrayList<>(exceptions));
    }
    return result;
  }
  

DecodePath逻辑和LoadPath很相似,最终是从decoders中循环取出ResourceDecoder对象,然后调用decoder.decode()来做最后的解析;另外,拿到解析结果之后,调用callback.onResourceDecoded(decoded);获取transform结果,这个我们本章节最后分析;

接下来我们分析ResourceDecoder

ResourceDecoder是一个接口

ResourceDecoder

/**
 * An interface for decoding resources.
 *
 * @param <T> The type the resource will be decoded from (File, InputStream etc).
 * @param <Z> The type of the decoded resource (Bitmap, Drawable etc).
 */
public interface ResourceDecoder<T, Z> {

  //通过参数,判断是否能够解析
  boolean handles(@NonNull T source, @NonNull Options options) throws IOException;

  @Nullable
  Resource<Z> decode(@NonNull T source, int width, int height, @NonNull Options options)
      throws IOException;
}

继续往下分析之前,先看一下ResourceDecoder<T,Z>泛型代表什么意思,从类注释上来看,T代码需要被解析的类型(例如:File,InputStream),Z是结果的类型(比如 Bitmap,Drawable),知道了这些,是弄清ResourceDecoder的基本前提;既然如此,我希望找到一个T为InputStream,Z为Bitmap的子类,Glide肯定有提供这个方案StreamBitmapDecoder,我们就以StreamBitmapDecoder为代表,分析ResourceDecoder;

分析解析流程

StreamBitmapDecoder.java

public class StreamBitmapDecoder implements ResourceDecoder<InputStream, Bitmap> {
  @Override
  public Resource<Bitmap> decode(@NonNull InputStream source, int width, int height,
      @NonNull Options options)
      throws IOException {

    // Use to fix the mark limit to avoid allocating buffers that fit entire images.
    final RecyclableBufferedInputStream bufferedStream;
    final boolean ownsBufferedStream;
    //获取bufferedStream
    if (source instanceof RecyclableBufferedInputStream) {
      bufferedStream = (RecyclableBufferedInputStream) source;
      ownsBufferedStream = false;
    } else {
      bufferedStream = new RecyclableBufferedInputStream(source, byteArrayPool);
      ownsBufferedStream = true;
    }
    ExceptionCatchingInputStream exceptionStream =
        ExceptionCatchingInputStream.obtain(bufferedStream);

    MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream);
    UntrustedCallbacks callbacks = new UntrustedCallbacks(bufferedStream, exceptionStream);//callbacks
    try {
      return downsampler.decode(invalidatingStream, width, height, options, callbacks);//最后的解析
    } finally {
      exceptionStream.release();
      if (ownsBufferedStream) {
        bufferedStream.release();
      }
    }
  }
}

decode方法经过一系列的流程,最终调用downsampler.decode(),最后的解析流程指向了Downsampler,简单来看一下这个类的介绍;

Downsampler.java

/**
 * Downsamples, decodes, and rotates images according to their exif orientation.
 */
public final class Downsampler {
}

这个类主要负责对图片进行:下采样,解析和根据exif方向旋转图片;关于Downsampler的细节分析不在这里进行,真个解析的流程分析到这里;

Transform调用

刚才在上文的DecodePath中分析调用callBack.onResourceDecoded()进行transform处理,我们简单分析一下transform的简单流程:

首先callBack是DecodeJob对象,最终代码到DecodeJob.onResourceDecoded()

DecodeJob.java

  <Z> Resource<Z> onResourceDecoded(DataSource dataSource,
      @NonNull Resource<Z> decoded) {
    @SuppressWarnings("unchecked")
    Class<Z> resourceSubClass = (Class<Z>) decoded.get().getClass();
    Transformation<Z> appliedTransformation = null;
    Resource<Z> transformed = decoded;
    if (dataSource != DataSource.RESOURCE_DISK_CACHE) {
      appliedTransformation = decodeHelper.getTransformation(resourceSubClass);
      transformed = appliedTransformation.transform(glideContext, decoded, width, height);
    }
    // TODO: Make this the responsibility of the Transformation.
    if (!decoded.equals(transformed)) {
      decoded.recycle();
    }
    ...省略
    return result;
  }

通过decodeHelper.getTransformation()获取目标的Transformation对象,decodeHelperDecodeHelper对象,getTransformation()流程分析:

DecodeHelper.java

 <Z> Transformation<Z> getTransformation(Class<Z> resourceClass) {
    Transformation<Z> result = (Transformation<Z>) transformations.get(resourceClass);//transformations是一个集合,在DecodeJob中初始化
    if (result == null) {
      for (Entry<Class<?>, Transformation<?>> entry : transformations.entrySet()) {
        if (entry.getKey().isAssignableFrom(resourceClass)) {//根据key和resourceClass匹配
          result = (Transformation<Z>) entry.getValue();
          break;
        }
      }
    }
    if (result == null) {
      if (transformations.isEmpty() && isTransformationRequired) {
        throw new IllegalArgumentException(
            "Missing transformation for " + resourceClass + ". If you wish to"
                + " ignore unknown resource types, use the optional transformation methods.");
      } else {
        return UnitTransformation.get();
      }
    }
    return result;
  }

DecodeHelper内部有一个Map集合transformations,这个集合在init()方法中初始化,init()DecodeJob中调用,getTransformation()根据Resource类型来遍历transformations获取目标Transformation并返回; 至于DecodeHelper集合transformations最初的调用,是从SingleRequest调用Engine.load()传递,最本质的来源还是RequestOptions.getTransformations(),所以transformations这个集合赋值流程是:SingleRequest->Engine->->DecodeJob->DecodeHelper-transformations,完毕。