本文首发于 vivo互联网技术 微信公众号 
链接:https://mp.weixin.qq.com/s/cPLkefpEb3w12-uoiqzTig
作者:连凌能

Android上图片加载的解决方案有多种,但是官方认可的是Glide。Glide提供简洁易用的api,整个框架也方便扩展,比如可以替换网络请求库,同时也提供了完备的缓存机制,应用层不需要自己去管理图片的缓存与获取,框架会分成内存缓存,文件缓存和远程缓存。本文不会从简单的使用着手,会把重点放在缓存机制的分析上。

一、综述

开始之前,关于Glide缓存请先思考几个问题:

Glide有几级缓存?

Glide内存缓存之间是什么关系?

Glide本地文件IO和网络请求是一个线程吗?如果不是,怎么实现线程切换?

Glide网络请求回来后数据直接返回给用户还是先存再返回?

加载开始入口从Engine.load()开始,先看下对这个方法的注释,

会先检查(Active Resources),如果有就直接返回,Active Resources没有被引用的资源会放入Memory Cache,如果Active Resources没有,会往下走。

检查Memory Cache中是否有需要的资源,如果有就返回,Memory Cache中没有就继续往下走。

检查当前在运行中的job中是否有改资源的下载,有就在现有的job中直接添加callback返回,不重复下载,当然前提是计算得到的key是一致的,如果还是没有,就会构造一个新的job开始新的工作。

* Starts a load for the given arguments.** <p>Must be called on the main thread.** <p>The flow for any request is as follows:* <ul>* <li>Check the current set of actively used resources, return the active resource if* present, and move any newly inactive resources into the memory cache.</li>* <li>Check the memory cache and provide the cached resource if present.</li>* <li>Check the current set of in progress loads and add the cb to the in progress load if* one is present.</li>* <li>Start a new load.</li>* </ul>

ok, find the source code.

二、内存缓存

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; EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options); // focus 1 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); } return null; } // focus 2 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); } return null; } // focus 3 EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache); if (current != null) { current.addCallback(cb); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Added to existing load", startTime, key); } return new LoadStatus(cb, current); } EngineJob<R> engineJob = engineJobFactory.build( key, isMemoryCacheable, useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrieveFromCache); DecodeJob<R> decodeJob = decodeJobFactory.build( glideContext, model, key, signature, width, height, resourceClass, transcodeClass, priority, diskCacheStrategy, transformations, isTransformationRequired, isScaleOnlyOrNoTransform, onlyRetrieveFromCache, options, engineJob); jobs.put(key, engineJob); engineJob.addCallback(cb); // focus 4 engineJob.start(decodeJob); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Started new load", startTime, key); } return new LoadStatus(cb, engineJob);}

先看到 focus 1,这一步会从 ActiveResources 中加载资源,首先判断是否使用内存缓存,否的话返回null;否则到 ActiveResources 中取数据:

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

接下来看下ActiveResources, 其实是用过弱引用保存使用过的资源。

final class ActiveResources { ... 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; } }); @VisibleForTesting final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>(); ...}

成功取到数据后回调类型也是内存缓存:

EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);if (cached != null) { cb.onResourceReady(cached, DataSource.MEMORY_CACHE); return null;}

接着回到Engine.load()中继续看到focus 2,如果在cache中找到就是remove掉,然后返回EngineResource,其中需要EngineResource进行acquire一下,这个后面再看,然后会把资源移到ActiveResources中,也就是上面提到的缓存:

// Engine.java private final MemoryCache cache; private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) { if (!isMemoryCacheable) { return null; } EngineResource<?> cached = getEngineResourceFromCache(key); if (cached != null) { cached.acquire(); activeResources.activate(key, cached); } return cached; } private EngineResource<?> getEngineResourceFromCache(Key key) { Resource<?> cached = cache.remove(key); final EngineResource<?> result; if (cached == null) { result = null; } else if (cached instanceof EngineResource) { // Save an object allocation if we've cached an EngineResource (the typical case). result = (EngineResource<?>) cached; } else { result = new EngineResource<>(cached, true /*isMemoryCacheable*/, true /*isRecyclable*/); } return result; }

其中cache是MemoryCache接口的实现,如果没设置,默认在build的时候是LruResourceCache, 也就是熟悉的LRU Cache:

// GlideBuilder.javaif (memoryCache == null) { memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());}

再看下EngineResource,主要是对资源增加了引用计数的功能:

// EngineResource.javaprivate final boolean isCacheable; private final boolean isRecyclable; private ResourceListener listener; private Key key; private int acquired; private boolean isRecycled; private final Resource<Z> 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; } boolean isCacheable() { return isCacheable; } @NonNull @Override public Class<Z> getResourceClass() { return resource.getResourceClass(); } @NonNull @Override public Z get() { return resource.get(); } @Override public int getSize() { return resource.getSize(); } @Override public void recycle() { if (acquired > 0) { throw new IllegalStateException("Cannot recycle a resource while it is still acquired"); } if (isRecycled) { throw new IllegalStateException("Cannot recycle a resource that has already been recycled"); } isRecycled = true; if (isRecyclable) { resource.recycle(); } } void acquire() { if (isRecycled) { throw new IllegalStateException("Cannot acquire a recycled resource"); } if (!Looper.getMainLooper().equals(Looper.myLooper())) { throw new IllegalThreadStateException("Must call acquire on the main thread"); } ++acquired; } void release() { if (acquired <= 0) { throw new IllegalStateException("Cannot release a recycled or not yet acquired resource"); } if (!Looper.getMainLooper().equals(Looper.myLooper())) { throw new IllegalThreadStateException("Must call release on the main thread"); } if (--acquired == 0) { listener.onResourceReleased(key, this); } }

在release后会判断引用计数是否为0,如果是0就会回调onResourceReleased,在这里就是Engine,然后会把资源从ActiveResources中移除,资源默认是可缓存的,因此会把资源放到LruCache中。

// Engine.java @Override public void onResourceReleased(Key cacheKey, EngineResource<?> resource) { Util.assertMainThread(); activeResources.deactivate(cacheKey); if (resource.isCacheable()) { cache.put(cacheKey, resource); } else { resourceRecycler.recycle(resource); } }// ActiveResources.java 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(); } } void deactivate(Key key) { ResourceWeakReference removed = activeEngineResources.remove(key); if (removed != null) { removed.reset(); } }

如果是回收呢,看看上面的EngineResource,如果引用计数为0并且还没与回收,就会调用真正的Resource.recycle(),看其中的一个BitmapResource是怎么回收的,就是放到Bitmap池中,也是用的LRU Cache,这个和今天的主题不相关,就不继续往下拓展。

// BitmapResource.java @Override public void recycle() { bitmapPool.put(bitmap); }

思路再拉到Engine.load()的流程中,接下来该看focus 3,这里再贴一下代码,如果job已经在运行了,那么直接添加一个回调后返回LoadStatus,这个可以允许用户取消任务:

// Engine.javaEngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);if (current != null) { current.addCallback(cb); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Added to existing load", startTime, key); } return new LoadStatus(cb, current);}// LoadStatus public static class LoadStatus { private final EngineJob<?> engineJob; private final ResourceCallback cb; LoadStatus(ResourceCallback cb, EngineJob<?> engineJob) { this.cb = cb; this.engineJob = engineJob; } public void cancel() { engineJob.removeCallback(cb); } }

接着往下看到focus 4, 到这里就需要创建后台任务去拉取磁盘文件或者发起网络请求。

三、磁盘缓存

// Engine.java EngineJob<R> engineJob = engineJobFactory.build( key, isMemoryCacheable, useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrieveFromCache); DecodeJob<R> decodeJob = decodeJobFactory.build( glideContext, model, key, signature, width, height, resourceClass, transcodeClass, priority, diskCacheStrategy, transformations, isTransformationRequired, isScaleOnlyOrNoTransform, onlyRetrieveFromCache, options, engineJob); jobs.put(key, engineJob); engineJob.addCallback(cb); engineJob.start(decodeJob); return new LoadStatus(cb, engineJob);

先构造两个job,一个是EngineJob,另外一个DecodeJob,其中DecodeJob会根据需要解码的资源来源分成下面几个阶段:

// DecodeJob.java /** * Where we're trying to decode data from. */ private enum Stage { /** The initial stage. */ INITIALIZE, /** Decode from a cached resource. */ RESOURCE_CACHE, /** Decode from cached source data. */ DATA_CACHE, /** Decode from retrieved source. */ SOURCE, /** Encoding transformed resources after a successful load. */ ENCODE, /** No more viable stages. */ FINISHED, }

在构造DecodeJob时会把状态置为INITIALIZE。

构造完两个 Job 后会调用 EngineJob.start(DecodeJob),首先会调用getNextStage来确定下一个阶段,这里面跟DiskCacheStrategy这个传入的磁盘缓存策略有关。

磁盘策略有下面几种:

**ALL: **缓存原始数据和转换后的数据

**NONE: **不缓存

**DATA: **原始数据,未经过解码或者转换

**RESOURCE: **缓存经过解码的数据

**AUTOMATIC(默认):**根据`EncodeStrategy`和`DataSource`等条件自动选择合适的缓存方

默认的AUTOMATIC方式是允许解码缓存的RESOURCE:

public static final DiskCacheStrategy AUTOMATIC = new DiskCacheStrategy() { @Override public boolean isDataCacheable(DataSource dataSource) { return dataSource == DataSource.REMOTE; } @Override public boolean isResourceCacheable(boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) { return ((isFromAlternateCacheKey && dataSource == DataSource.DATA_DISK_CACHE) || dataSource == DataSource.LOCAL) && encodeStrategy == EncodeStrategy.TRANSFORMED; } @Override public boolean decodeCachedResource() { return true; } @Override public boolean decodeCachedData() { return true; } };

所以在 getNextStage 会先返回Stage.RESOURCE_CACHE,然后在start中会返回diskCacheExecutor,然后开始执行DecodeJob:

// EngineJob.javapublic void start(DecodeJob<R> decodeJob) { this.decodeJob = decodeJob; GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor(); executor.execute(decodeJob);}// DecodeJob.java boolean willDecodeFromCache() { Stage firstStage = getNextStage(Stage.INITIALIZE); return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE; } private Stage getNextStage(Stage current) { switch (current) { case INITIALIZE: return diskCacheStrategy.decodeCachedResource() ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE); case RESOURCE_CACHE: return diskCacheStrategy.decodeCachedData() ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE); case DATA_CACHE: // Skip loading from source if the user opted to only retrieve the resource from cache. return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE; case SOURCE: case FINISHED: return Stage.FINISHED; default: throw new IllegalArgumentException("Unrecognized stage: " + current); } }

DecodeJob会回调run()开始执行, run()中调用runWrapped执行工作,这里runReason还是RunReason.INITIALIZE ,根据前面的分析指导这里会获得一个ResourceCacheGenerator,然后调用runGenerators:

// DecodeJob.java private void runWrapped() { switch (runReason) { case INITIALIZE: stage = getNextStage(Stage.INITIALIZE); currentGenerator = getNextGenerator(); runGenerators(); break; case SWITCH_TO_SOURCE_SERVICE: runGenerators(); break; case DECODE_DATA: decodeFromRetrievedData(); break; default: throw new IllegalStateException("Unrecognized run reason: " + runReason); } } 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); } }

在 runGenerators 中,会调用 startNext,目前currentGenerator是ResourceCacheGenerator, 那么就是调用它的startNext方法:

// DecodeJob.java 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; } } // We've run out of stages and generators, give up. if ((stage == Stage.FINISHED || isCancelled) && !isStarted) { notifyFailed(); } }

看下ResourceCacheGenerator.startNext(), 这里面就是重点逻辑了,首先从Registry中获取支持资源类型的ModelLoader(其中ModelLoader是在构造Glide的时候传进去), 然后从ModelLoader中构造LoadData,接着就能拿到DataFetcher,(关于ModelLoader/LoadData/DataFetcher之间的关系不在本次范围内,后面有机会再另写)通过它的loadData方法加载数据:

@Override public boolean startNext() { List<Key> sourceIds = helper.getCacheKeys(); if (sourceIds.isEmpty()) { return false; } List<Class<?>> resourceClasses = helper.getRegisteredResourceClasses(); if (resourceClasses.isEmpty()) { if (File.class.equals(helper.getTranscodeClass())) { return false; } } while (modelLoaders == null || !hasNextModelLoader()) { resourceClassIndex++; if (resourceClassIndex >= resourceClasses.size()) { sourceIdIndex++; if (sourceIdIndex >= sourceIds.size()) { return false; } resourceClassIndex = 0; } Key sourceId = sourceIds.get(sourceIdIndex); Class<?> resourceClass = resourceClasses.get(resourceClassIndex); Transformation<?> transformation = helper.getTransformation(resourceClass); currentKey = new ResourceCacheKey(// NOPMD AvoidInstantiatingObjectsInLoops helper.getArrayPool(), sourceId, helper.getSignature(), helper.getWidth(), helper.getHeight(), transformation, resourceClass, helper.getOptions()); cacheFile = helper.getDiskCache().get(currentKey); if (cacheFile != null) { sourceKey = sourceId; modelLoaders = helper.getModelLoaders(cacheFile); modelLoaderIndex = 0; } } loadData = null; boolean started = false; while (!started && hasNextModelLoader()) { ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++); loadData = modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions()); if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) { started = true; loadData.fetcher.loadData(helper.getPriority(), this); } } return started; }

如果在Resource中找不到需要的资源,那么startNext就会返回false,在runGenerators中就会进入循环体内:

接着会重复上面执行getNextStage,由于现在Stage已经是RESOURCE_CACHE,所以接下来会返回DataCacheGenerator,执行逻辑和上面的ResourceCacheGenerator是一样的,如果还是没有找到需要的,进入循环体内。

此时getNextStage会根据用于是否设置只从磁盘中获取资源,如果是就会通知失败,回调onLoadFailed;如果不是就设置当前Stage为Stage.SOURCE,接着往下走。

状态就会进入循环内部的if条件逻辑里面,调用reschedule。

在reschedule把runReason设置成SWITCH_TO_SOURCE_SERVICE,然后通过callback回调。

DecodeJob中的callback是EngineJob传递过来的,所以现在返回到EngineJob。

在EngineJob中通过getActiveSourceExecutor切换到网络线程池中,执行DecodeJob,下面就准备开始发起网络请求。四、网络缓存

在Stage.SOURCE阶段,通过getNextGenerator返回的是SourceGenerator,所以目前的currentGenerator就是它。

流程还是一样的,SourceGenerator还是调用startNext方法,获取到对应的DataFetcher,这里其实是HttpUrlFetcher,发起网络请求。

// DecodeJob.java private void runGenerators() { ... while (!isCancelled && currentGenerator != null && !(isStarted = currentGenerator.startNext())) { stage = getNextStage(stage); currentGenerator = getNextGenerator(); if (stage == Stage.SOURCE) { reschedule(); return; } } ... } @Override public void reschedule() { runReason = RunReason.SWITCH_TO_SOURCE_SERVICE; callback.reschedule(this); }// EngineJob.java @Override public void reschedule(DecodeJob<?> job) { getActiveSourceExecutor().execute(job); }

先缓一缓,本文其实到了上面已经可以结束了,Glide涉及到的五级缓存都已经涉及到了,是真的就可以结束了吗?不是的,网络请求回来和缓存还有关系吗?接着看到HttpUrlFetcher,下载成功后回调onDataReady,其中callback是SourceGenerator:

// HttpUrlFetcher.java@Override public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) { long startTime = LogTime.getLogTime(); try { InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders()); callback.onDataReady(result); } catch (IOException e) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Failed to load data for url", e); } callback.onLoadFailed(e); } finally { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime)); } } }// EngineJob.java @Override public void reschedule(DecodeJob<?> job) { getActiveSourceExecutor().execute(job); }

正常情况会进入if判断逻辑里面,赋值dataToCache,然后回调cb.reschedule,而cb就是DecodeJob构造SourceGenerator的时候传入,cb是DecodeJob。

// SourceGenerator.java @Override public void onDataReady(Object data) { DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy(); if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) { dataToCache = data; cb.reschedule(); } else { cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher, loadData.fetcher.getDataSource(), originalKey); } }

DecodeJob在reschedule回调EngineJob,最后还是回到SourceGenerator中的startNext()逻辑。

// DecodeJob.java 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); } } @Override public void reschedule() { runReason = RunReason.SWITCH_TO_SOURCE_SERVICE; callback.reschedule(this); }

和第一次进来的逻辑不一样,现在dataToCache != null,进入第一个if逻辑。

在逻辑里面调用cacheData,逻辑很明显,保持数据到本地,然后会构造一个DataCacheGenerator。

而DataCacheGenerator前面已经分析过了,就是用来加载本地原始数据的,这回会加载成功,返回true。

// SourceGenerator.java@Override public boolean startNext() { if (dataToCache != null) { Object data = dataToCache; dataToCache = null; cacheData(data); } if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) { return true; } ... } 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); } finally { loadData.fetcher.cleanup(); } sourceCacheGenerator = new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this); }

接下来就是一系列的回调了:

DataCacheGenerator的startNext逻辑里面会给DataFetcher传递自身作为callback,在加载本地数据成功后回调onDataReady。

// DataCacheGenerator @Override public boolean startNext() { ... loadData = null; boolean started = false; while (!started && hasNextModelLoader()) { ... if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) { started = true; loadData.fetcher.loadData(helper.getPriority(), this); } } return started; } @Override public void onDataReady(Object data) { cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey); }

而cb现在是SourceGenerator传递过来,SourceGenerator再回调它自己的cb,是DecodeJob在构造它的时候传过来。

// SourceGenerator.java @Override public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) { cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey); }// DecodeJob.java @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; callback.reschedule(this); } else { try { decodeFromRetrievedData(); } finally { GlideTrace.endSection(); } } }

在上面SourceGenerator把DecodeJob切换到ActiveSourceExecutor线程中执行,还记得一开始DecodeJob是在哪启动的吗?在EngineJob中启动,然后是把DecodeJob放到diskCacheExecutor中执行。

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

所以上面在DecodeJob的onDataFetcherReady会走到第一个if逻辑里面,然后赋值runReason = RunReason.DECODE_DATA,再一次回调Engine.reschedule,将工作线程切换到ActiveSourceExecutor。

// Engine.java @Override public void reschedule(DecodeJob<?> job) { // Even if the job is cancelled here, it still needs to be scheduled so that it can clean itself // up. getActiveSourceExecutor().execute(job); }//

然后还是走到DecodeJob, 现在会进入DECODE_DATA分支,在这里面会调用ResourceDecoder把数据解码:

private void runWrapped() { switch (runReason) { case INITIALIZE: stage = getNextStage(Stage.INITIALIZE); currentGenerator = getNextGenerator(); runGenerators(); break; case SWITCH_TO_SOURCE_SERVICE: runGenerators(); break; case DECODE_DATA: decodeFromRetrievedData(); break; default: throw new IllegalStateException("Unrecognized run reason: " + runReason); } }

解码成功后调用notifyComplete(result, dataSource);

private void notifyComplete(Resource<R> resource, DataSource dataSource) { setNotifiedOrThrow(); callback.onResourceReady(resource, dataSource);}五、总结

现在回答一下开头的几个问题。

1、有几级缓存?五级,分别是什么?

活动资源 (Active Resources)

内存缓存 (Memory Cache)

资源类型(Resource Disk Cache)

原始数据 (Data Disk Cache)

网络缓存2、Glide内存缓存之间是什么关系?

专门画了一幅图表明这个关系,言简意赅。

3、Glide本地文件IO和网络请求是一个线程吗?

明显不是,本地IO通过diskCacheExecutor,而网络IO通过ActiveSourceExecutor

4、Glide网络请求回来后数据直接返回给用户还是先存再返回?

不是直接返回给用户,会在SourceGenerator中构造一个DataCacheGenerator来取数据。