Glide
特性
- Glide 可以自动帮助你处理片状网络连接:它可以监听用户的连接状态并在用户重新连接到网络时重启之前失败的请求。如果 Glide 检测到你的应用拥有 ACCESS_NETWORK_STATE 权限,Glide 将自动监听连接状态而不需要额外的改动。
- Glide 可以自动帮你处理 Activity 或者 Fragment 的声明周期,当 Activity 和 Fragment 销毁时取消网络请求
- Glide 可以根据控件大小,压缩成控件大小的图片
- 在内存不足的时候清除内存中的缓存数据
配置
1
2
3
4
5
6
7
8
9
repositories {
google()
mavenCentral()
}
dependencies {
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
}
Glide 是如何绑定 Activity 、Fragment 生命周期的
Glide 并没有直接使用 jetpack 的 Lifecycle ,可能是考虑到兼容性问题,但思路和 Lifecycle 相同:
通过在 Fragment、Activity 内添加一个 Fragment 感知 Fragment、Activity 的声明周期;
而这个感知声明周期的 Fragment 在 Glide 中就是 SupportRequestManagerFragment 和 RequestManagerFragment ;其内部实现基本一致的,只不过SupportRequestManagerFragment继承的是 androidx.fragment.app.Fragment,RequestManagerFragment 继承的是 android.app.Fragment
RequestManagerFragment 如果感知的是 Fragment 的生命周期,还会添加到 Activity 对应的 RequestManagerFragment 的 childRequestManagerFragments 内,因此 Fragment 的 Glide 请求不止能感知 Fragment 的生命周期还能感知 Activity的 声明周期
有关 Glide 生命周期的类如下:
- com.bumptech.glide.manager.ActivityFragmentLifecycle
- com.bumptech.glide.manager.Lifecycle
- com.bumptech.glide.manager.LifecycleListener
其逻辑很简单就是观察者模式,监听了 onStart onStop onDestroy 三个声明周期
相关类
- RequestManager 一个 RequestManager 用来管理一个 Activity 或者 Fragment 内的所有 Glide 请求,负责 Glide 请求的的生命周期管理
- RequestManagerRetriever 根据 Glide.with() 的 view,context,activity,fragment 等传值,找到或者创建对应的 RequestManager
- RequestManagerFragment,SupportRequestManagerFragment 向 Activity 或者 Fragment 内添加 一个Fragment 用来感知其生命周期
- Request
- SingleRequest
- ThumbnailRequestCoordinator
- ErrorRequestCoordinator
- RequestCoordinator
- ThumbnailRequestCoordinator
- ErrorRequestCoordinator
从源码的角度看 Glide 加载图片的流程 (4.12.0)
1
Glide.with(imageView).load("imageUrl").into(imageView)
- Glide.with(imageView)
1 2 3
public static RequestManager with(@NonNull View view) { return getRetriever(view.getContext()).get(view); }
- 展开 getRetriever(view.getContext())
1 2 3 4
private static RequestManagerRetriever getRetriever(@Nullable Context context) { ... return Glide.get(context).getRequestManagerRetriever(); }
- 展开 Glide.get(context)
1 2 3 4 5 6 7 8 9 10 11 12 13
public static Glide get(@NonNull Context context) { if (glide == null) { GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules(context.getApplicationContext()); synchronized (Glide.class) { if (glide == null) { checkAndInitializeGlide(context, annotationGeneratedModule); } } } return glide; }
checkAndInitializeGlide 的作用是 检查 创建 初始化 Glide对象
Glide.get(context) 总结来说就是获取到全局唯一的 Glide 对象 - Glide.getRequestManagerRetriever 就是获取到 全局唯一的 RequestManagerRetriever
- 调用 RequestManagerRetriever.get(view) 获取到 view 所对应的 RequestManager
- 展开 getRetriever(view.getContext())
- RequestManager.load(“imageUrl”)
1 2 3
public RequestBuilder<Drawable> load(@Nullable String string) { return asDrawable().load(string); }
配置一些默认参数返回 RequestBuilder
- Request.into(imageView)
1 2 3 4 5 6 7 8 9
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) { ... return into( glideContext.buildImageViewTarget(view, transcodeClass), /*targetListener=*/ null, requestOptions, Executors.mainThreadExecutor()); }
- glideContext.buildImageViewTarget(view, transcodeClass)
transcodeClass 是最终结果的类型在此次调用中就是 Drawable.class
展开buildImageViewTarget1 2 3
public <X> ViewTarget<ImageView, X> buildImageViewTarget(@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) { return imageViewTargetFactory.buildTarget(imageView, transcodeClass); }
展开ImageViewTargetFactory.buildTarget
1 2 3 4 5 6 7 8 9 10 11
public <Z> ViewTarget<ImageView, Z> buildTarget( @NonNull ImageView view, @NonNull Class<Z> clazz) { if (Bitmap.class.equals(clazz)) { return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view); } else if (Drawable.class.isAssignableFrom(clazz)) { return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view); } else { throw new IllegalArgumentException( "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)"); } }
根据设置的 transcodeClass 生成不同的ViewTaget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> { public DrawableImageViewTarget(ImageView view) { super(view); } /** @deprecated Use {@link #waitForLayout()} instead. */ // Public API. @SuppressWarnings({"unused", "deprecation"}) @Deprecated public DrawableImageViewTarget(ImageView view, boolean waitForLayout) { super(view, waitForLayout); } @Override protected void setResource(@Nullable Drawable resource) { view.setImageDrawable(resource); } }
- RequestBuilder.into()
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
private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options, Executor callbackExecutor) { Preconditions.checkNotNull(target); if (!isModelSet) { throw new IllegalArgumentException("You must call #load() before calling #into()"); } Request request = buildRequest(target, targetListener, options, callbackExecutor); Request previous = target.getRequest(); if (request.isEquivalentTo(previous) && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { if (!Preconditions.checkNotNull(previous).isRunning()) { previous.begin(); } return target; } requestManager.clear(target); target.setRequest(request); requestManager.track(target, request); return target; }
- 这块代码有一个重要的逻辑,先说这个逻辑解决了什么问题:当 RecyclerView 使用 Glide 的时候有可能会发生 url 还没有加载成功,View 已经被回收复用,这时候 RequestOption 有可能已经被修改
那是如何解决的呢?
先看 Request previous = target.getRequest();1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
public Request getRequest() { Object tag = getTag(); Request request = null; if (tag != null) { if (tag instanceof Request) { request = (Request) tag; } else { throw new IllegalArgumentException( "You must not call setTag() on a view Glide is targeting"); } } return request; } private Object getTag() { return view.getTag(tagId); }
target.setRequest(request);
1 2 3 4 5 6 7
public void setRequest(@Nullable Request request) { setTag(request); } private void setTag(@Nullable Object tag) { isTagUsedAtLeastOnce = true; view.setTag(tagId, tag); }
由上述代码可知 Glide 将 Request 保存到 View.tag 中,新的 Request 会和先前的 Request 做比较 如果相同则复用之前 Reqeust ;如果不同则清除之前的 Request ( requestManager.clear(target) ),使用新的 Request ( requestManager.track(target, request) )
- 接下来继续看 执行 Request 请求的部分
1 2 3 4
synchronized void track(@NonNull Target<?> target, @NonNull Request request) { targetTracker.track(target); requestTracker.runRequest(request); }
进入 runRequest
1 2 3 4 5 6 7 8 9 10 11 12
public void runRequest(@NonNull Request request) { requests.add(request); if (!isPaused) { request.begin(); } else { request.clear(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Paused, delaying request"); } pendingRequests.add(request); } }
此处的 request 为 SingleRequest,因此实际调用的为 SingleRequest.begin()
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
public void begin() { synchronized (requestLock) { ... if (status == Status.COMPLETE) { onResourceReady( resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false); return; } ... status = Status.WAITING_FOR_SIZE; if (Util.isValidDimensions(overrideWidth, overrideHeight)) { onSizeReady(overrideWidth, overrideHeight); } else { target.getSize(this); } if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE) && canNotifyStatusChanged()) { target.onLoadStarted(getPlaceholderDrawable()); } if (IS_VERBOSE_LOGGABLE) { logV("finished run method in " + LogTime.getElapsedMillis(startTime)); } } }
如果已经加载完成即 Status.COMPLETE 则使用缓存数据,如果没有加载完成则置为等待确认Size状态 Status.WAITING_FOR_SIZE ,然后判断 overrideWidth, overrideHeight 是否是用户设置的值,如果不是则从 target.getSize(this) 获取数据
从之前分析我们已得知 target 实际为 DrawableImageViewTarget 而 getSize 是在其父类 ViewTarget 内实现的1 2 3
public void getSize(@NonNull SizeReadyCallback cb) { sizeDeterminer.getSize(cb); }
SizeDeterminer 这个类的作用就是获取View的大小,实现方式就是通过 getViewTreeObserver 监听 onPreDraw 方法,重新从View获取测量后的宽高,最终会回调到 SingleRequest.onSizeReady()
SingleRequest.onSizeReady 调用 Engine.load(…) 方法 具体可看下面缓存部分分析 如果在内存缓存中没找到对应的图片资原调用了 Engine.waitForExistingOrStartNewJob 方法- 调用 EngineJob.start
- 调用 GlideExecutor.execute
- 调用 ExecutorService.excute ,可以看出这一个线程执行器,所以下一步需要查看的方法是 DecodeJob.run
- 调用 DecodeJob.runWrapped();
- 调用 DecodeJob.runGenerators
- 调用 DecodeJob.getNextGenerator
- 调用 SourceGenerator.startNext
- 调用 DataFetcher.getDataSource
- 调用 SourceGenerator.startNextLoad
- 调用 loadData.fetcher.loadData
- 调用 HttpUrlFetcher.loadData
- 调用 HttpUrlFetcher.loadDataWithRedirects 这里面就是实际用 HttpURLConnection 进行网络请求的部分
- glideContext.buildImageViewTarget(view, transcodeClass)
transcodeClass 是最终结果的类型在此次调用中就是 Drawable.class
关系
- 一个App 只有一个 Glide 对象 也只有一个 RequestManagerRetriever 对象
- 一个 Activity 或者 Fragment 对应一个 RequestManager 管理对应 Activity 或者 Fragment 的多个 Request
- 每个 Request 就是一次加载图片请求
3. 缓存分析
Engine:管理通过参数获取图片对象的流程,包括 缓存,网络请求 ,Engine.load 方法是 Engine 的入口
默认的策略叫做 AUTOMATIC ,它会尝试对本地和远程图片使用最佳的策略。当你加载远程数据(比如,从URL下载)时,AUTOMATIC 策略仅会存储未被你的加载过程修改过(比如,变换,裁剪–译者注)的原始数据,因为下载远程数据相比调整磁盘上已经存在的数据要昂贵得多。对于本地数据,AUTOMATIC 策略则会仅存储变换过的缩略图,因为即使你需要再次生成另一个尺寸或类型的图片,取回原始数据也很容易。
DiskCacheStrategy 这个类管理各级缓存启用策略
3.1 内存缓存
- ActiveResources:View 正在展示的图片资源;由 ActiveResources 实现,内部资源由 WeakReference 持有,可以保护这些图片不会被 LurCache 算法回收。
- MemoryCache:最近被加载过并仍存在于内存中;Lru算法管理;由 LruResourceCache 实现,上层抽象接口为 MemoryCache, 继承于 LruCache
内存缓存加载流程:
- 根据图片地址、高度、变换、签名等生成Key
- 如果 ActiveResources 有该缓存,将当前图片 ActiveResources 计数器加一;如果 ActiveResources 没有获取到数据,从 MemoryCache 中获取资原
- 将资原从 MemoryCache 中删除添加到ActiveResources 中,并将当前图片 ActiveResources 计数器加一
- 当 View 被移除,该图片 ActiveResources 计数器减一
- 当 ActiveResources 计数器归0,将图片从 ActiveResources 计数器移除,添加到 MemoryCache 中
为什么设计两种内存缓存?
MemoryCache 是使用 Lru 算法实现的,因此有可能会把正在使用的缓存误伤,我们还在使用着它呢就被移除内存缓存了。添加 ActiveResources 是读正在使用中的图片的一种保护,使用的时候先从 MemoryCache 中移出,用完了再把它重新加到 MemoryCache 中。
3.2 硬盘缓存 (可配置,默认智能)
- 缓存转换后的图片
- 缓存原始图片
- 从网络获取数据
在看源码之前先描述几个概念
- model
- 是指我们通过 RequestBuilder.load() 方法传入不同的类型,比如 URI,”url”,resourceId 等,model 会根据他们加载方式的不同,进行分类
- modelLoader
- 用来加载 model 对应图片的加载器,不同类型的 model 加载器也不同,比如 url 就是从网路加载,而 ResourceId 就是通过 Resources.getDrawable() 加载
他们被统一管理在 ModelLoaderRegistry 中 可以通过 GlideContext.getRegistry().getModelLoaders(…); 获取对应 ModelLoader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public <R> LoadStatus Engine.load(...) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
// 生成 Key 判断图片是否相同的标识
EngineKey key =
keyFactory.buildKey(...);
EngineResource<?> memoryResource;
synchronized (this) {
// 通过 Key 尝试从内存中获取缓存
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
return waitForExistingOrStartNewJob(...);
}
}
3.1 从内存中获取缓存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 从内存缓存中获取数据
@Nullable
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
if (!isMemoryCacheable) {
return null;
}
// 从正在使用的资源中获取缓存图片数据
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
return active;
}
// 从内存 LurCache 中获取缓存图片数据
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
return cached;
}
return null;
}
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
@Nullable
private EngineResource<?> loadFromActiveResources(Key key) {
EngineResource<?> active = activeResources.get(key);
if (active != null) {
// 使用计数+1
active.acquire();
}
return active;
}
private EngineResource<?> loadFromCache(Key key) {
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
// 使用计数+1
cached.acquire();
// 添加到 “正在使用的缓存 activeResources” 中
activeResources.activate(key, cached);
}
return cached;
}
private EngineResource<?> getEngineResourceFromCache(Key key) {
Resource<?> cached = cache.remove(key);
final EngineResource<?> result;
if (cached == null) {
result = null;
} else if (cached instanceof EngineResource) {
// Save an object allocation if we've cached an EngineResource (the typical case).
result = (EngineResource<?>) cached;
} else {
result =
new EngineResource<>(
cached, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ true, key, /*listener=*/ this);
}
return result;
}
3.2 从磁盘或者网络获取数据
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
private <R> LoadStatus waitForExistingOrStartNewJob(...) {
// 查看当前是否有加载同一张图片的 Job
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
// 如果有相同图片的Job,直接复用,将获取图片的callback 添加到 Job 中
current.addCallback(cb, callbackExecutor);
return new LoadStatus(cb, current);
}
// 创建加载图片的 Job
EngineJob<R> engineJob =
engineJobFactory.build();
// 创建从磁盘缓存或者网络获取到图片的 Job
DecodeJob<R> decodeJob =
decodeJobFactory.build();
// 添加到 Jobs 列表中
jobs.put(key, engineJob);
// 将回调 callback 添加到 Job 中
engineJob.addCallback(cb, callbackExecutor);
// 启动 Job
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
public synchronized void EngineJob.start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
executor.execute(decodeJob);
}
分析 EngineJob.start 可知:如果设置使用磁盘缓存,最终调用的是 diskCacheExecutor.execute(decodeJob) , 溯源追查可得 diskCacheExecutor 其实是通过 GlideExecutor.newDiskCacheExecutor() 创建的对象,其实质就是一个线程池,所以关注的重点应该在 DecodeJob.run 方法
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
@Override
public void DecodeJob.run() {
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
// 其实质代码在 runWrapped 中
runWrapped();
} catch (CallbackException e) {
throw e;
} catch (Throwable t) {
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
throw t;
} finally {
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
// 下个状态为 Stage.RESOURCE_CACHE
stage = getNextStage(Stage.INITIALIZE);
// getNextGenerator 根据 stage 获取到 ResourceCacheGenerator
currentGenerator = getNextGenerator();
// 执行 currentGenerator.startNext 方法
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
// 定义了两种磁盘缓存资原获取器 ResourceCacheGenerator 和 DataCacheGenerator
// SourceGenerator 是最原始的资原获取方式,可能是网络,也可能是本地图片,也可能是资原Id
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);
}
}
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
// 执行 currentGenerator.startNext 如果找到对应资原返回 true 跳出 while 循环 ,如果没有找到对应资原返回 false 继续执行 while 循环
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);、
// ResourceCacheGenerator 的下一个是 DataCacheGenerator
currentGenerator = getNextGenerator();
// 当stage == Stage.SOURCE 表示磁盘缓存没有找到图片,这时 currentGenerator = SourceGenerator
if (stage == Stage.SOURCE) {
// reschedule 会将 runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
// 调用 Engine.reschedule(DecodeJob) 所以最终还会走到 DecodeJob.run -> DecodeJob.runGenerators()方法只不过换了一个线程池,
reschedule();
return;
}
}
// We've run out of stages and generators, give up.
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
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
@Override
public boolean ResourceCacheGenerator.startNext() {
// 从缓存中获取 key ,一般是 uri 地址的一个包装类 , GlideUrl
List<Key> sourceIds = helper.getCacheKeys();
if (sourceIds.isEmpty()) {
return false;
}
// 获取已注册类型的列表 [class com.bumptech.glide.load.resource.gif.GifDrawable, class android.graphics.Bitmap, class android.graphics.drawable.BitmapDrawable]
List<Class<?>> resourceClasses = helper.getRegisteredResourceClasses();
if (resourceClasses.isEmpty()) {
if (File.class.equals(helper.getTranscodeClass())) {
return false;
}
throw new IllegalStateException(
"Failed to find any load path from "
+ helper.getModelClass()
+ " to "
+ helper.getTranscodeClass());
}
while (modelLoaders == null || !hasNextModelLoader()) {
resourceClassIndex++;
if (resourceClassIndex >= resourceClasses.size()) {
sourceIdIndex++;
if (sourceIdIndex >= sourceIds.size()) {
return false;
}
resourceClassIndex = 0;
}
Key sourceId = sourceIds.get(sourceIdIndex);
Class<?> resourceClass = resourceClasses.get(resourceClassIndex);
// 获取对应的转换类: GifDrawable 对应 GifDrawableTransformation ;Bitmap 对应 BitmapTransformation 的继承类,可能是 FitCenter; BitmapDrawable 对应 DrawableTransformation
Transformation<?> transformation = helper.getTransformation(resourceClass);
// 生成搜索文件的 key
currentKey =
new ResourceCacheKey(
helper.getArrayPool(),
sourceId,
helper.getSignature(),
helper.getWidth(),
helper.getHeight(),
transformation,
resourceClass,
helper.getOptions());
//实际调用为 DiskLruCacheWrapper.get()
//DiskLruCacheWrapper.get() 获取的是转换后的图片和没有转换的图片合集
// 也就是说磁盘的两级缓存都存放在一个地方,只不过计算 key 的参数不同
cacheFile = helper.getDiskCache().get(currentKey);
if (cacheFile != null) {
sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(
cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
// 上面的代码查找要加载的图片对应的缓存文件,包括大小和变换等配置都要一致
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
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
@Override
public boolean DataCacheGenerator.startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if (sourceIdIndex >= cacheKeys.size()) {
return false;
}
Key sourceId = cacheKeys.get(sourceIdIndex);
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
// 获取对应的缓存文件 例如:/data/user/0/com.ooftf.myapplication/cache/image_manager_disk_cache/bdb1f03fcbbdec6f06ffba88a10e2c3f348f5546aa100bb06d05de1486c0ce21.0
cacheFile = helper.getDiskCache().get(originalKey);
if (cacheFile != null) {
this.sourceKey = sourceId;
// 根据 cacheFile 类型获取对应的加载器 [com.bumptech.glide.load.model.ByteBufferFileLoader, com.bumptech.glide.load.model.FileLoader com.bumptech.glide.load.model.FileLoader, com.bumptech.glide.load.model.UnitModelLoader]
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(
cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
// ByteBufferFileLoader.ByteBufferFetcher
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
// 从缓存文件中加载数据到 ByteBuffer
@Override
public void ByteBufferFetcher.loadData(
@NonNull Priority priority, @NonNull DataCallback<? super ByteBuffer> callback) {
ByteBuffer result;
try {
result = ByteBufferUtil.fromFile(file);
callback.onDataReady(result);
} catch (IOException e) {
callback.onLoadFailed(e);
}
}
3.3 从网络(泛指非缓存加载,并不一定是网络加载)获取数据 SourceGenerator
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
@Override
public boolean startNext() {
// 网络加载 dataToCache 为 null,加载成功后会给 dataToCache 赋值
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()) {
// 获取到对应的 modelLoader
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
// 开始调用 loadData 从网络(泛指非缓存加载)加载图片
startNextLoad(loadData);
}
}
return started;
}
private void startNextLoad(final LoadData<?> toStart) {
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback<Object>() {
@Override
public void onDataReady(@Nullable Object data) {
if (isCurrentRequest(toStart)) {
onDataReadyInternal(toStart, data);
}
}
@Override
public void onLoadFailed(@NonNull Exception e) {
if (isCurrentRequest(toStart)) {
onLoadFailedInternal(toStart, e);
}
}
});
}
// 非缓存加载成功
void onDataReadyInternal(LoadData<?> loadData, Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
// dataToCache 赋值,在 startNext 有用到
dataToCache = data;
// 从代码可知 cb 就是 DecodeJob,因此最终还会调用到 startNext(),会走到分支 cacheData()
cb.reschedule();
} else {
cb.onDataFetcherReady(
loadData.sourceKey,
data,
loadData.fetcher,
loadData.fetcher.getDataSource(),
originalKey);
}
}
private void cacheData(Object dataToCache) {
long startTime = LogTime.getLogTime();
try {
Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
DataCacheWriter<Object> writer =
new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
// 将图片数据存储到磁盘中
helper.getDiskCache().put(originalKey, writer);
} finally {
loadData.fetcher.cleanup();
}
// sourceCacheGenerator 赋值,在 SourceGenerator.startNext 方法中会被调用,DataCacheGenerator 会加载数据成功,最终通知各个 Callback 获取图片成功
sourceCacheGenerator =
new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
}
AppGlideModule 分析
- 通过 annotationProcessor + javapoet 根据 AppGlideModule 的注解生成 GlideApp 对象
- 从 Glide 调用变为 GlideApp 调用
- GlideApp 在保留了Glide api 的同时,可以添加自定义方法,方便封装
API
- 预加载
1
GlideApp.with(AppHolder.app).load(url).preload()
- 仅从缓存加载
1
RequestOptions().onlyRetrieveFromCache(true)
相关辅助库
- com.github.bumptech.glide:okhttp3-integration:4.11.0
将 Glide 内部实现由默认的 HttpURLConnection 改为 OkHttp - com.github.bumptech.glide:recyclerview-integration:4.11.0
在用户滑动 RecyclerView 时自动加载稍微超前一些的图片。配合使用正确的图片尺寸和高效率的磁盘缓存策略,这个库可以显著减少用户滑动图片列表时看到的加载指示器的数量。 - glide-transformations