Glide : https://github.com/bumptech/glide
version : v4.9.0
从一个简单的API调用来讲Glide源码内部工作原理。1
2
3Glide.with(context)
.load(url)
.into(imageView);
Glide.with
Glide
1 |
|
with有很多的重载方法,接受不同的参数,比如Context、Activity、FragmentActivity、Fragment、View等。但是最终都调用到getRetriever方法。然后再调用requestManagerRetriever的get方法。1
2
3
4
5
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
Preconditions.checkNotNull(context, "You cannot start a load on a not yet attached View or a Fragment where getActivity() returns null (which usually occurs when getActivity() is called before the Fragment is attached or after the Fragment is destroyed).");
return get(context).getRequestManagerRetriever();
}
get(context)方法获取到Glide的单例,创建单例时会进行Glide初始化操作,此时会生成requestManagerRetriever对象。getRetriever返回创建的requestManagerRetriever对象。
RequestManagerRetriever
RequestManagerRetriever的get方法也有很多重载方法,跟之前我们看到的with方法一样,我们拿其中的一个方法来说明get(FragmentActivity),内部有两个逻辑。1.如果是子线程,就会调用get(context)方法,进而调用getApplicationManager方法。2.否则调用supportFragmentGet方法。
1 |
|
在 supportFragmentGet中新建了一个没有UI的SupportRequestManagerFragment,然后把fragment添加到Activity中,这样fragment就和Activity的生命周期同步了。而在 fragment中,有着onStart() onStop()的生命周期监听。因此,Glide就实现了在Fragment和 Activity的图片加载请求的生命周期管理。
我们可以看出,supportFragmentGet 中返回的 requestManager 是和当前 fragment 生命周期绑定在一起的。
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
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
private SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingSupportRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
`
总结
在Glide.with中,主要做了两件事。
- Glide的初始化
- Glide请求的生命周期管理
RequestManager.load
load方法有很多重载方法,可以加载不同的资源类型,这里我们拿load(string)来说,内部先调用了asDrawable方法返回了RequestBuilder,RequestBuilder是通过Builder模式来构造Request的。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
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
return asDrawable().load(drawable);
}
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
public RequestBuilder<Drawable> load(@Nullable File file) {
return asDrawable().load(file);
}
"deprecation") (
public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return asDrawable().load(resourceId);
}
"deprecation") (
public RequestBuilder<Drawable> load(@Nullable URL url) {
return asDrawable().load(url);
}
public RequestBuilder<Drawable> load(@Nullable byte[] model) {
return asDrawable().load(model);
}
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
RequestManager#asDrawable
as方法中创建了RequestBuilder的实例。1
2
3
4
5
6
7
8
9
10
11
12
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
RequestBuilder的构造函数中,初始化了监听器,和默认的请求配置。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15protected RequestBuilder(
@NonNull Glide glide,
RequestManager requestManager,
Class<TranscodeType> transcodeClass,
Context context) {
this.glide = glide;
this.requestManager = requestManager;
this.transcodeClass = transcodeClass;
this.context = context;
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
this.glideContext = glide.getGlideContext();
initRequestListeners(requestManager.getDefaultRequestListeners());
apply(requestManager.getDefaultRequestOptions());
}
1 |
|
配置项有很多,这些我们比较熟悉:
- diskCacheStrategy: 磁盘缓存策略
- errorPlaceholder: 出错时的占位图
- placeholderDrawable: 加载时候的占位图
- overrideWidth、overrideHeight: 加载图片固定宽高
RequestBuilder#load
1 |
|
load方法内部调用了loadGeneric方法,loadGeneric方法把model赋值给全局变量model,然后设置标记isModelSet为true,标记已经调用过load方法了。最后返回了当前的RequestBuilder对象。
总结
在RequestManager.load方法中,
- 调用asDrawable方法创建RequestBuilder对象
- 对RequestBuilder对象进行默认值设置
- load不同类型的资源,并标记。
RequestBuilder.into
RequestBuilder
into方法最终会调用重载方法into(target,targetListener,options,callbackExecutor)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
35public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
1 | private <Y extends Target<TranscodeType>> Y into( |
RequestManager
- TargetTracker.track() 方法会对当前 Target 的生命周期进行管理;
- RequestTracker.runRequest() 方法对当前请求进行管理;
1
2
3
4synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
RequestTracker
当 Glide 未处于暂停状态的时候,会直接使用 Request.begin() 方法开启请求。1
2
3
4
5
6
7
8
9
10
11
12public 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);
}
}
SingleRequest
在 begin 方法中,会根据有没有强制设置图片宽度来分为两部分处理:
- 设置了,直接调用 onSizeReady
- 没设置,会去调用 target.getSize 。做的事情就是给 view 添加 addOnPreDrawListener 。这样的话,在绘制之前获取到了 view 的宽高,然后再回调 onSizeReady。
所以,说到底,最后都是会调用 onSizeReady 的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 synchronized void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
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));
}
}
在 onSizeReady 中将状态更改为 Status.RUNNING ,并调用 engine 的 load() 方法。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
public synchronized 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));
}
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,
callbackExecutor);
if (status != Status.RUNNING) {
loadStatus = null;
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
Engine
load方法有五个步骤
- 构造此图片的缓存 key
- 从Map中获取(弱引用)
- 从内存缓存中获取
- 创建EngineJob对象,创建DecodeJob对象,调用engineJob的start方法,传递decodeJob进去
EngineJob 内部维护了线程池,用来管理资源加载,已经当资源加载完毕的时候通知回调。 DecodeJob 继承了 Runnable,是线程池当中的一个任务。就像上面那样,我们通过调用 engineJob.start(decodeJob) 来开始执行图片加载的任务。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
88public synchronized <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,
Executor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
//1.构造此图片的缓存 key
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//2.从Map中获取
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
//3.从内存缓存中获取
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
//4. 创建EngineJob对象
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
//5.创建DecodeJob对象
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb, callbackExecutor);
//调用engineJob的start方法,传递decodeJob进去
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
EngineJob
1 | public synchronized void start(DecodeJob<R> decodeJob) { |
DecodeJob
在 run 方法中,当前任务没有被取消的话,会进入到 runWrapped() 方法。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
public void run() {
//1.在run方法中,当前任务没有被取消的话,会进入到 runWrapped() 方法。
runWrapped();
}
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//2.第一次进入初始化
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
//4.运行
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
//3. 第一次没有缓存,所以进入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;
//4. 先执行SourceGenerator的startNext方法。
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();
}
}
SourceGenerator
1 | private final DecodeHelper<?> helper; |
因为之前我们的想法是加载网络上的 url 图片,所以这里的 loadData 就对应着 HttpGlideUrlLoader
, fetcher 就是 HttpUrlFetcher 。
HttpUrlFetcher
建立连接,获取图片流,调用回调方法。
loadDataWithRedirects 中会去调用 HttpURLConnection 加载网络上的图片数据。加载完之后,会回调 onDataReady 方法。这个回调一直从 HttpUrlFetcher 中一直回调到 SourceGenerator 中。所以下面就来看看 SourceGenerator.onDataReady1
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
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data for url", e);
}
callback.onLoadFailed(e);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
}
}
}
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
Map<String, String> headers) throws IOException {
if (redirects >= MAXIMUM_REDIRECTS) {
throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
} else {
try {
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
throw new HttpException("In re-direct loop");
}
} catch (URISyntaxException e) {
// Do nothing, this is best effort.
}
}
urlConnection = connectionFactory.build(url);
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
urlConnection.setConnectTimeout(timeout);
urlConnection.setReadTimeout(timeout);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
urlConnection.setInstanceFollowRedirects(false);
urlConnection.connect();
stream = urlConnection.getInputStream();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (isHttpOk(statusCode)) {
return getStreamForSuccessfulRequest(urlConnection);
} else if (isHttpRedirect(statusCode)) {
String redirectUrlString = urlConnection.getHeaderField("Location");
if (TextUtils.isEmpty(redirectUrlString)) {
throw new HttpException("Received empty or null redirect url");
}
URL redirectUrl = new URL(url, redirectUrlString);
cleanup();
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else if (statusCode == INVALID_STATUS_CODE) {
throw new HttpException(statusCode);
} else {
throw new HttpException(urlConnection.getResponseMessage(), statusCode);
}
}
SourceGenerator
在 onDataReady 中,会去判断如果 data 不为空并且磁盘缓存可以缓存的情况下,会调用 cb.reschedule(); 。这其实是调用了 DecodeJob 的 reschedule 方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
cb.reschedule();
} else {
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
public void onLoadFailed(@NonNull Exception e) {
cb.onDataFetcherFailed(originalKey, e, loadData.fetcher, loadData.fetcher.getDataSource());
}
DecodeJob
1 |
|
在这里,设置 runReason 为 RunReason.SWITCH_TO_SOURCE_SERVICE ,这很关键,在下面代码中会用到。然后再调用 callback.reschedule(this) 。其实就是调用了 EngineJob 的 reschedule 方法。
EngineJob
1 |
|
reschedule 方法摆明了就是让 DecodeJob 把 run 方法再跑一遍。之前说过,DecodeJob 的 run 方法里面大部分的逻辑其实是在 runWrapped 中的。
DecodeJob
这代码很熟悉,之前我们的流程到过这里。不同的是,之前的 runReason 是 INITIALIZE 。而现在的 runReason 是 SWITCH_TO_SOURCE_SERVICE 。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
接着 SWITCH_TO_SOURCE_SERVICE 的逻辑是直接调用 runGenerators 方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 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();
}
}
SourceGenerator
这里的 currentGenerator 还是之前的 SourceGenerator ,所以还是调用 SourceGenerator.startNext 。
1 |
|
这次调用 SourceGenerator.startNext 其实是建立磁盘缓存,直接来看 cacheData 方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 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 创建一个对象,所以 sourceCacheGenerator 不再是 null
sourceCacheGenerator =
new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
}
这里的主要逻辑是构建一个用于将数据缓存到磁盘上面的 DataCacheGenerator。DataCacheGenerator 的流程基本与 SourceGenerator 一致,也就是根据资源文件的类型找到 ModelLoader,然后使用 DataFetcher 加载缓存的资源。与之前不同的是,这次是用 DataFecher 来加载 File 类型的资源。也就是说,当我们从网络中拿到了数据之后 Glide 会先将其缓存到磁盘上面,然后再从磁盘上面读取图片并将其显示到控件上面。所以,当从网络打开了输入流之后 SourceGenerator 的任务基本结束了,而后的显示的任务都由 DataCacheGenerator 来完成。
再回过头来看看 SourceGenerator.startNext 方法,在 cacheData 后面会对 sourceCacheGenerator 进行判断。由于上面已经把 sourceCacheGenerator 对象 new 出来了。所以接着就直接走 DataCacheGenerator 的 startNext 方法了。所以上面这段话就很好理解了。1
2
3if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
那么,这里我们对 DataCacheGenerator 的逻辑就省略了。DataCacheGenerator 中的流程最终会走到
ByteBufferFetcher 。
之前的 SourceGenerator 对应着 HttpUrlFetcher ,而 DataCacheGenerator 对应着 ByteBufferFetcher 。
ByteBufferFetcher
磁盘缓存好之后,再从文件中读取图片的字节流。回调给 DataCacheGenerator1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super ByteBuffer> callback) {
ByteBuffer result;
try {
//1.把图片的字节流再从磁盘缓存中读取出来
result = ByteBufferUtil.fromFile(file);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to obtain ByteBuffer for file", e);
}
callback.onLoadFailed(e);
return;
}
//2.回调给 DataCacheGenerator 的 onDataReady 方法
callback.onDataReady(result);
}
DataCacheGenerator
1 |
|
DataCacheGenerator 会回调 DecodeJob 的 onDataFetcherReady 方法。
DecodeJob
1 |
|
这里我们可以看下,当 resource 最终获取到后,是通过 notifyEncodeAndRelease 来通知任务完成的。这在后面的代码解析中会讲到。现在,我们就来看看关键的逻辑,接着调用 decodeFromData 。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
36private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data,
DataSource dataSource) throws GlideException {
try {
if (data == null) {
return null;
}
long startTime = LogTime.getLogTime();
Resource<R> result = decodeFromFetcher(data, dataSource);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded result " + result, startTime);
}
return result;
} finally {
fetcher.cleanup();
}
}
"unchecked") (
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
throws GlideException {
LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
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));
} finally {
rewinder.cleanup();
}
}
LoadPath
1 | public Resource<Transcode> load(DataRewinder<Data> rewinder, @NonNull Options options, int width, |
然后会调用 DecodePath 的 decode 方法。
DecodePath
在 decode 中做了三件事:
- decodeResource 将原始数据转换成我们原始图片的过程;
- callback.onResourceDecoded 是当得到了原始图片之后对图片继续处理过程;
- transcoder.transcode 会使用 BitmapDrawableTranscoder 包装一层,即对 Drawable 进行延迟初始化处理。
1 | public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height, |
ByteBufferBitmapDecoder
1 |
|
它最终会在 Downsampler 的 decodeStream() 方法中调用 BitmapFactory 的 decodeStream() 方法来从输入流中得到 Bitmap。在 Downsampler 内部还会维持一个 BitmapPool ,用来复用 Bitmap 。有兴趣的同学可以看下这一块的代码,这里就不过多展示了。接下来,就来看看上面 callback.onResourceDecoded 的逻辑。callback.onResourceDecoded 会调用 DecodeJob.onResourceDecoded 方法。
DecodeJob
1 |
|
主要的逻辑是根据我们设置的参数进行变化。也就是说,如果我们使用了 centerCrop 等参数,那么这里将会对其进行处理。这里的 Transformation 是一个接口,它的一系列的实现都是对应于 scaleType 等参数的。
到了这里, Glide 所有加载图片、处理图片的逻辑都讲完了。剩下的,就是将图片显示到 ImageView 上面了。
我们再回过头来看之前讲到 DecodeJob.notifyEncodeAndRelease 方法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
34private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
if (resource instanceof Initializable) {
((Initializable) resource).initialize();
}
Resource<R> result = resource;
LockedResource<R> lockedResource = null;
if (deferredEncodeManager.hasResourceToEncode()) {
lockedResource = LockedResource.obtain(resource);
result = lockedResource;
}
notifyComplete(result, dataSource);
stage = Stage.ENCODE;
try {
if (deferredEncodeManager.hasResourceToEncode()) {
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
if (lockedResource != null) {
lockedResource.unlock();
}
}
// Call onEncodeComplete outside the finally block so that it's not called if the encode process
// throws.
onEncodeComplete();
}
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
//回调 EngineJob 的 onResourceReady 方法。
callback.onResourceReady(resource, dataSource);
}
EngineJob
1 |
|
CallResourceReady
1 | private class CallResourceReady implements Runnable { |
SingleRequest
1 |
|
最后调用 onResourceReady((Resource) resource, (R) received, dataSource);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
36private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
if (glideContext.getLogLevel() <= Log.DEBUG) {
Log.d(GLIDE_TAG, "Finished loading " + result.getClass().getSimpleName() + " from "
+ dataSource + " for " + model + " with size [" + width + "x" + height + "] in "
+ LogTime.getElapsedMillis(startTime) + " ms");
}
isCallingCallbacks = true;
try {
boolean anyListenerHandledUpdatingTarget = false;
if (requestListeners != null) {
for (RequestListener<R> listener : requestListeners) {
anyListenerHandledUpdatingTarget |=
listener.onResourceReady(result, model, target, dataSource, isFirstResource);
}
}
anyListenerHandledUpdatingTarget |=
targetListener != null
&& targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
发现上面的代码调用了 target.onResourceReady(result, animation);
这里的 target 一般都是 ImageViewTarget 。ImageViewTarget 是个抽象类。
ImageViewTarget
1 |
|
setResource(resource) 是抽象方法,我们到子类中看看。我们挑 DrawableImageViewTarget 来看看吧。
DrawableImageViewTarget
1 |
|
显示了图片,大功告成。
总结
into方法内部比较复杂,这里就分析到这里。关于Glide的其他功能解析,后面会详细讲。