前言
在上一篇文章中介绍了Glide基本的调用流程,总结起来就是Engine
是真正加载资源的入口,SingleRequest
起到连接RequestManager
、Target
和Engine
的纽带关系,本文将承接上文,探讨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和容器,诸如engineJobFactory
、decodeJobFactory
和Jobs
、activeResources
等,各种参数先不一一介绍,我们看load()方法,这是整个调用的出发点;我在代码中已经注释的很清晰,下面再梳理一遍流程:
load流程
- 通过keyFactory和请求参数,创建EngineKey对象key;
- 调用
loadFromActiveResources()
方法,尝试从活动的Resources中获取active; - 如果步骤2命中,直接回调cb.onResourceReady(),并返回,不命中,执行步骤4;
- 调用
loadFromCache()
方法,尝试从内存缓存中获取cached; - 如果步骤4命中,直接回调cb.onResourceReday(),并返回,不命中,执行步骤6;
- 尝试从jobs中获取匹配key的正在执行的EngineJob current;
- 如果步骤6命中,把回调添加到current并返回,不命中,执行步骤8;
- 通过engineJobFactory创建新的EngineJob对象engineJob;
- 根据decodeJobFactory创建新的DecodeJob对象decodeJob;
- 把engineJob添加进jobs中,讲回调cb设置到engineJob中;
- 执行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分析一定要区分EngineResource
和Resource
,这俩不是一个对象;
牛掰的弱引用复用机制
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)
解除ref
对resource
强引用。
内存缓存第二阶段
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
对象,急于分析流程,我们直接进入DecodeJob
的run()
方法开始:
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
就是来区分这一状态的:
- INITIALIZE 第一次调用run,这次执行的目的是从CACHE中获取缓存
- SWITCH_TO_SOURCE_SERVICE 如果从CACHE中获取失败,转成从数据源读取,是第二次调用run
- DECODE_DATA 缓存获取成功,对数据进行解析
分阶段读取DiskCache
接下来分析DiskCache,后面出现缓存
和Cache
的字眼,如无特殊标识,都是指DiskCache
;
在读取缓存之前,还有两个概念:stage
和Generator
,在搞清除概念之前,先讲一下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
,最终会执行这个Generator
的startNext()
方法,否则,while循环获取loadData
,如果满足条件,执行loadData.fetcher.loadData(helper.getPriority(), this);
,最后一个参数this
是DataFetcher.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
是谁?
cb
是FetcherReadyCallback
类型,这个cb
在SourceGenerator
构造方法中传入,SourceGenerator
是在DecodeJob
中创建的,真正是cb
是DecodeJob
,所以代码定位到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
的主要流程:
- 通过 helper.getLoadData()获取loadData,调用loadData.fetcher.loadData()来执行load;
- DecodeJob接受load回调,如果需要进行cache,回调EngineJob执行cache相关的Generator;
- 如果可以解析,调用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
对象,decodeHelper
是DecodeHelper
对象,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,完毕。