Hiten's Blog.

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

字数统计: 6.9k阅读时长: 32 min
2019/01/04 Share

前言

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

本章要讨论的内容:

  • Engine的工作流程;
  • 内存缓存ActiveResource原理剖析;
  • 内存缓存MemoryCache基本原理;
  • EngineJob和DecodeJob的工作原理;

在讨论Engine之前,还是从调用它的地方开始SingleReques.onSizeReady

从Engine开始

SingleRequest.java

1
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.java

1
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
165
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

1
2
3
4
5
6
7
8
9
10
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

1
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
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

1
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
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

1
2
3
4
5
6
7
8
9
10
11
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

1
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
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

1
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
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

1
2
3
4
5
6
7
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

1
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
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

1
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
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
//根据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

1
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
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

1
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是谁?
cbFetcherReadyCallback类型,这个cbSourceGenerator构造方法中传入,SourceGenerator是在DecodeJob中创建的,真正是cbDecodeJob,所以代码定位到DecodeJob.onDataFetcherReady()reschedule()方法.

DecodeJob.java

1
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的主要流程:

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

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

解析部分

1
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
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

1
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
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

1
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
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 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

1
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
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

1
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<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

1
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,完毕。

CATALOG
  1. 1. 前言
  2. 2. 从Engine开始
    1. 2.1. Engine的初始化和加载流程
  3. 3. 内存缓存第一阶段
    1. 3.1. ActiveResource缓存原理
    2. 3.2. 牛掰的弱引用复用机制
  4. 4. 内存缓存第二阶段
    1. 4.1. LruResourceCache
  5. 5. 内存缓存小结
  6. 6. 真正的Job
  7. 7. 分阶段读取DiskCache
    1. 7.1. 获取数据:以SourceGenerator为例
    2. 7.2. 解析部分
    3. 7.3. ResourceDecoder
    4. 7.4. 分析解析流程
    5. 7.5. Transform调用