前言
在上一篇文章中介绍了Glide基本的调用流程,总结起来就是Engine
是真正加载资源的入口,SingleRequest
起到连接RequestManager
、Target
和Engine
的纽带关系,本文将承接上文,探讨Glide的加载流程。
本章要讨论的内容:
- Engine的工作流程;
- 内存缓存ActiveResource原理剖析;
- 内存缓存MemoryCache基本原理;
- EngineJob和DecodeJob的工作原理;
在讨论Engine之前,还是从调用它的地方开始SingleReques.onSizeReady
从Engine开始
SingleRequest.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47@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.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165public 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.java1
2
3
4
5
6
7
8
9
10private 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.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155final 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.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28class 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.java1
2
3
4
5
6
7
8
9
10
11public 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.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26private 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.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39public 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.java1
2
3
4
5
6
7public 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.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51public 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.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43//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()
方法:
1 | //根据stage选择NextGenerator |
在runGenerators()
方法中有一个while循环,推进了stage的前进,循环的主要的判断是currentGenerator.startNext()
,而这个startNext()
方法又是读取Cache的新开端。
上面说到根据不同的stage创建不同的Generator
,我们仅以SourceGenerator
来分析;
获取数据:以SourceGenerator为例
SourceGenerator.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57class 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.java1
2
3
4
5
6
7
8
9
10
11@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.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26@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
;
解析部分
1 | private void decodeFromRetrievedData() { |
解析方法在DecodeJob
中几斤周转,最终从decodeHelper.getLoadPath()
得到LoadPath
对象,然后调用path.load()
执行真正的加载逻辑;
LoadPath.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33public 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
1 | public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height, |
DecodePath
逻辑和LoadPath
很相似,最终是从decoders
中循环取出ResourceDecoder
对象,然后调用decoder.decode()
来做最后的解析;另外,拿到解析结果之后,调用callback.onResourceDecoded(decoded);
获取transform结果,这个我们本章节最后分析;
接下来我们分析ResourceDecoder
:
ResourceDecoder
是一个接口
ResourceDecoder
1 | /** |
继续往下分析之前,先看一下ResourceDecoder<T,Z>
泛型代表什么意思,从类注释上来看,T
代码需要被解析的类型(例如:File,InputStream),Z
是结果的类型(比如 Bitmap,Drawable),知道了这些,是弄清ResourceDecoder的基本前提;既然如此,我希望找到一个T为InputStream
,Z为Bitmap
的子类,Glide
肯定有提供这个方案StreamBitmapDecoder
,我们就以StreamBitmapDecoder
为代表,分析ResourceDecoder
;
分析解析流程
StreamBitmapDecoder.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32public 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.java1
2
3
4
5/**
* 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
1 | <Z> Resource<Z> onResourceDecoded(DataSource dataSource, |
通过decodeHelper.getTransformation()
获取目标的Transformation
对象,decodeHelper
是DecodeHelper
对象,getTransformation()
流程分析:
DecodeHelper.java1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<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,完毕。