博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【笔记整理】Glide 4.9.0 执行流程源码解析
阅读量:3564 次
发布时间:2019-05-20

本文共 17735 字,大约阅读时间需要 59 分钟。

对于源码的分析,是基于 Glide 最简单的使用的流程进行的:

Glide.with(MainActivity.this).load("url of image resource").into(view);

1. with() 方法

with() 方法会传入当前 activityfragment 等,目的就是为了获取对应的 context,然后根据该 context 来得到 RequestManagerRetriever 对象,再进一步得到 RequestManager 对象。并且 Glide 会根据我们传入 with() 方法的参数来确定图片加载的生命周期。

这里,对于 context 只有两种情况,Application 类型的与非 Application 类型的。

对于 Application 类型的,会得到 RequestManagerRetriever#applicationManager(虽然实质上也是 RequestManager 对象,只不过比较特殊一点,因为 Application 对象的生命周期即应用程序的生命周期,因此 Glide 并不需要做什么特殊的处理,它自动就是和应用程序的生命周期是同步的,如果应用程序关闭的话,Glide 的加载也会同时终止)。而非 Applicatuion 类型的则会得到普通的 RequestManager 对象。

在内部,先得到 Glide#requestManagerRetriever,然后通过 requestManagerRetriever#get() 方法得到 RequestManager 对象。

requestManagerRetriever#get() 执行的过程中,会向当前的 Activity 或者 Fragment 添加一个隐藏的 Fragment(名为 SupportRequestManagerFragment 或者 RequestManagerFragment),这个 Fragment 是为了监听 Activity 或者 Fragment 的生命周期,使得能够感知其销毁,从而停止图片的加载。

public RequestManager get(@NonNull Fragment fragment) {
Preconditions.checkNotNull(fragment.getActivity(), "You cannot start a load on a fragment before it is attached or after it is destroyed"); if (Util.isOnBackgroundThread()) {
return get(fragment.getActivity().getApplicationContext()); } else {
FragmentManager fm = fragment.getChildFragmentManager(); // 调用 supportFragmentGet() 来得到 RequestManager 对象 return supportFragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible()); }}private RequestManager supportFragmentGet( @NonNull Context context, @NonNull FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
// 进一步调用 getSupportRequestManagerFragment() 来获取 SupportRequestManagerFragment SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint, isParentVisible); // 然后得到 SupportRequestManagerFragment 中的 RequestManager 对象(如果为 null 则构建一个并 // 设置) 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;}// 在 getSupportRequestManagerFragment() 中,会根据 FragmentManager 来得到对应的 // SupportRequestManagerFragment(如果为 null 则实例化一个并添加)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); // 添加 SupportRequestManagerFragment fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current;}

2. load(String) 方法

RequestManager#load(String)

public RequestBuilder
load(@Nullable String string) {
return asDrawable().load(string);}public RequestBuilder
asDrawable() {
return as(Drawable.class);}public
RequestBuilder
as( @NonNull Class
resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);}

其中 asDrawable() 最终会构建 RequestBuilder<Drawable> 对象,其中对于 load() 传入 String 类型参数时,RequestBuilder#resourceClassDrawable.classresourceClass 用于指定加载资源被交付的类型。

比如 RequestBuilder<GifDrawable> asGif()RequestBuilder<File> asFile()RequestBuilder<Bitmap> asBitmap() 等等。其中,asDrawable() 是默认的,会根据情况来确定加载的资源被交付时的类型。

然后 load(String) 会进一步调用 RequestBuilder#loadGeneric(),这里只是将传递进来的 url 字符串设置给成员变量 model。

private RequestBuilder
loadGeneric(@Nullable Object model) {
this.model = model; isModelSet = true; return this;}

因此,load() 主要用于生成一个 RequestBuilder,该对象在后面用于对于资源的请求。

3. into() 方法

经过 Glide.with(Context).load(String) 之后,最终会得到 RequestBuilder<Drawable>,因此 Glide.with(Context).into(ImageView) 实际上就是调用 RequestBuilder<Drawable>#into(ImageView)

public ViewTarget
into(@NonNull ImageView view) {
Util.assertMainThread(); Preconditions.checkNotNull(view); // RequestBuilder 继承自 BaseRequestOptions BaseRequestOptions
requestOptions = this; // 根据 ImageView 的 scaleType 来判断是否克隆并设置额外的 option if (!requestOptions.isTransformationSet() && requestOptions.isTransformationAllowed() && view.getScaleType() != null) {
// Clone in this method so that if we use this RequestBuilder to load into a View and then // into a different target, we don't retain the transformation applied based on the previous // View's scale type. switch (view.getScaleType()) {
case CENTER_CROP: requestOptions = requestOptions.clone().optionalCenterCrop(); break; ... default: // Do nothing. } } // 然后进一步调用冲载的 into() 方法 return into( glideContext.buildImageViewTarget(view, transcodeClass), /*targetListener=*/ null, requestOptions, Executors.mainThreadExecutor());}

(1)其中 glideContext.buildImageViewTarget(view, transcodeClass) 会构建出一个 ViewTarget<ImageView, X> 对象。这里的 transcodeClass 就是前面在 new RequestBuilder 对象时设置的,即 Drawable.class,且 glideContextGlideContext

// GlideContext.javapublic 
ViewTarget
buildImageViewTarget( @NonNull ImageView imageView, @NonNull Class
transcodeClass) {
// 进一步调用 ImageViewTargetFactory#buildTarget() return imageViewTargetFactory.buildTarget(imageView, transcodeClass);}// ImageViewTargetFactory.javapublic
ViewTarget
buildTarget(@NonNull ImageView view, @NonNull Class
clazz) { if (Bitmap.class.equals(clazz)) { return (ViewTarget
) new BitmapImageViewTarget(view); } else if (Drawable.class.isAssignableFrom(clazz)) { return (ViewTarget
) new DrawableImageViewTarget(view); } else { throw new IllegalArgumentException( "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)"); }}

最终,会得到实际为 DrawableImageViewTargetViewTarget 对象,该对象是用来最终展示图片用的。

(2)进一步调用的 into() 重载方法为:

// RequestBuilder.java// target 为前面所说的 DrawableImageViewTarget 实例// targetListener 为 null// options 是从上一个方法传递过来的// callbackExecutor 为 Executors.mainThreadExecutor()private 
> Y into( @NonNull Y target, @Nullable RequestListener
targetListener, BaseRequestOptions
options, Executor callbackExecutor) {
Preconditions.checkNotNull(target); if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()"); } // 根据传递进来的参数构建出 Request // 在主流程中,就得到一个 SingleRequest 对象,里面 Request request = buildRequest(target, targetListener, options, callbackExecutor); Request previous = target.getRequest(); ... return target; } requestManager.clear(target); target.setRequest(request); // 执行 request requestManager.track(target, request); return target;}

requestManager.track(target, request) 中会调用 requestTracker.runRequest(request)

// RequestTracker.javapublic 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); }}

先判断 Glide 当前是不是处理暂停状态,如果不是暂停状态就调用 Requestbegin() 方法来执行开启请求,否则的话就先将 Request 添加到待执行队列里面,等暂停状态解除了之后再执行。

正常情况下,Request 的具体类型会是 SingleRequest,因此进入到 SingleRequest#begin()

// SingleRequest.javapublic synchronized void begin() {
assertNotCallingCallbacks(); stateVerifier.throwIfRecycled(); startTime = LogTime.getLogTime(); // 如果 model 等于 null,model 也就是我们在第二步 load() 方法中传入的图片 URL 地址, // 这个时候会调用 onException() 方法。 // 在 onException() 中会调用 setErrorPlaceholder()。 // 而在 setErrorPlaceholder() 根据实际情况来选择调用 fallback()、error()、placeholder() 这几个方法 // 时设置的图片显示到 ImageView 上 if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth; height = overrideHeight; } // Only log at more verbose log levels if the user has set a fallback drawable, because // fallback Drawables indicate the user expects null models occasionally. int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG; onLoadFailed(new GlideException("Received null model"), logLevel); return; } ... status = Status.WAITING_FOR_SIZE; if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// 如果使用了 override() API 为图片指定了一个固定的宽高 onSizeReady(overrideWidth, overrideHeight); } else {
// 没有指定则调用 target.getSize() // target.getSize() 方法的内部会根据 ImageView 的 // layout_width 和 layout_height 值做一系列的计算,来算出图片应该的宽高 // 计算完之后,它也会调用 onSizeReady() 方法 target.getSize(this); } ...}

根据前面的流程,正常情况下都会进入到 onSizeReady() 方法:

public synchronized void onSizeReady(int width, int height) {
... status = Status.RUNNING; float sizeMultiplier = requestOptions.getSizeMultiplier(); this.width = maybeApplySizeMultiplier(width, sizeMultiplier); this.height = maybeApplySizeMultiplier(height, sizeMultiplier); 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); // This is a hack that's only useful for testing right now where loads complete synchronously // even though under any executor running on any thread but the main thread, the load would // have completed asynchronously. if (status != Status.RUNNING) {
loadStatus = null; }}

然后进一步调用 Engine#load(),这一部分就是加载资源的关键了

// Engine.javapublic synchronized 
LoadStatus load( ...) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0; // 首先根据目标资源的相关参数得到对应的 key 值 EngineKey key = keyFactory.buildKey(model, signature, width, height, transform resourceClass, transcodeClass, options); // 然后从 ActiveResources 内存缓存中去取 EngineResource
active = loadFromActiveResources(key, isMemoryCacheable); // 如果取到了则直接回调后续方法 if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE); return null; } // 如果在 ActiveResources 内存缓存中没有取到,则再去基于 LruCache 的内存缓存中去取 EngineResource
cached = loadFromCache(key, isMemoryCacheable); if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE); return null; } // 从缓存中查找 key 对应的任务,即加载资源的任务 EngineJob
current = jobs.get(key, onlyRetrieveFromCache); if (current != null) {
// 如果取到了则表示任务已经完成,进行相应的回调即可 current.addCallback(cb, callbackExecutor); return new LoadStatus(cb, current); } // 否则,在内存中没有获取到缓存的资源,则构建相关任务,从磁盘或者远程加载 // 构建一个新的引擎任务 EngineJob
engineJob = engineJobFactory.build( ...); // 构建解码任务 DecodeJob
decodeJob = decodeJobFactory.build( ...); jobs.put(key, engineJob); engineJob.addCallback(cb, callbackExecutor); engineJob.start(decodeJob); return new LoadStatus(cb, engineJob);}

可以看到,则 Engine#load() 中,会先从内存缓存中去获取目标资源,如果没有,才会进一步去从磁盘缓存或者远程去加载资源(当然,这部分是后面的内容)。

上面说到会构建 EngineJobDecodeJob

其中,EngineJob 对象的主要作用就是用来开启线程的,为后面的异步加载图片做准备。

DecodeJob 对象实现了 Runnable 接口,然后会调用 engineJob.start(decodeJob) 来启动 decodeJob

// EngineJob.javapublic synchronized void start(DecodeJob
decodeJob) {
this.decodeJob = decodeJob; // 得到对应的 GlideExecutor,用于提交并执行 decodeJob GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor(); executor.execute(decodeJob);}

GlideExecutor 有好几种类型的,diskCacheExecutor、sourceExecutor、sourceUnlimitedExecutor、animationExecutor,不同类型的 GlideExecutor 用于从不同的地方 load/decode/transform data,这里的地方指的磁盘缓存、Glide 自己的缓存区等。

不同的 GlideExecutor 对象内部会持有不同的线程池,执行 GlideExecutor#execute(),会间接调用线程池的 execute() 方法。

因此这里可以理解为将 decodeJob 提交到对应的线程池去处理。因为 decodeJobRunnable,当其被处理的时候,实际上会调用其 run() 方法。

// DecodeJob.javapublic void run() {
... // Methods in the try statement can invalidate currentFetcher, so set a local variable here to // ensure that the fetcher is cleaned up either way. DataFetcher
localFetcher = currentFetcher; try {
if (isCancelled) {
notifyFailed(); return; } runWrapped(); } ...}private void runWrapped() {
switch (runReason) {
case INITIALIZE: // 1、得到 stage stage = getNextStage(Stage.INITIALIZE); // 2、根据 stage 得到对应的 Generator currentGenerator = getNextGenerator(); runGenerators(); break; case SWITCH_TO_SOURCE_SERVICE: runGenerators(); break; case DECODE_DATA: decodeFromRetrievedData(); break; default: throw new IllegalStateException("Unrecognized run reason: " + runReason); }}private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE: // decodeCachedResource() 为 true 表示尝试 decode 缓存的被转换的图片 return diskCacheStrategy.decodeCachedResource() ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE); case RESOURCE_CACHE: // decodeCachedData() 为 true 表示尝试 decode 缓存的原始图片 return diskCacheStrategy.decodeCachedData() ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE); case DATA_CACHE: // Skip loading from source if the user opted to only retrieve the resource from cache. // 如果用户选择只用缓存中检索资源,则跳过从源头加载 return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE; case SOURCE: case FINISHED: return Stage.FINISHED; default: throw new IllegalArgumentException("Unrecognized stage: " + current); }}private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE: // 对应被转换的图片的缓存的 Generator return new ResourceCacheGenerator(decodeHelper, this); case DATA_CACHE: // 对应原始图片的缓存的 Generator return new DataCacheGenerator(decodeHelper, this); case SOURCE: // 对应加载的图片的 Generator(此时) 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; while (!isCancelled && currentGenerator != null // currentGenerator 执行加载逻辑 && !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage); currentGenerator = getNextGenerator(); if (stage == Stage.SOURCE) {
reschedule(); return; } } // We've run out of stages and generators, give up. if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed(); } // Otherwise a generator started a new load and we expect to be called back in // onDataFetcherReady.}

run() 方法中,会进一步调用 runWrapped(),此时会走 case INITIALIZE 的语句。

此时会根据不同的场景的获取不同的 Generator 来获取资源。这里主要针对 SourceGenerator 进行分析,其表示从数据源头请求数据(如通过网路从远程加载)。

(对于 ResourceCacheDataCache,是针对磁盘缓存来说的,因为当资源图片从网络加载后之后,可能会经过一些列的转换,而被转换后的图片资源则对应为 Resource,而没有经过转换的原始图片,则对应为 Source。相关内容在讲关于缓存的章节有说:)

后续的逻辑,主要是在 runGenerators() 中调用 currentGenerator.startNext() 来执行加载逻辑。

// SourceGenerator.javapublic boolean startNext() {
... sourceCacheGenerator = null; loadData = null; boolean started = false; while (!started && hasNextModelLoader()) {
// 1. 从 DecodeHelper 的数据加载集合中, 获取一个数据加载器 loadData = helper.getLoadData().get(loadDataListIndex++); if (loadData != null && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource()) || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true; // 2. 使用加载器中 fetcher 执行数据加载 // 网络的 url 资源对应的就是 HttpGlideUrlLoader,它对应的 ModelLoader.LoadData 中的 // fetcher 为 HttpUrlFetcher 类型 loadData.fetcher.loadData(helper.getPriority(), this); } } return started;}

对于从网络加载资源,是由 HttpUrlFetcher#loadData() 来处理的。

// HttpUrlFetcher.javapublic void loadData(    @NonNull Priority priority, @NonNull DataCallback
callback) {
long startTime = LogTime.getLogTime(); try {
// 获取网络图片, 内部使用了 HttpURLConnection 实现, 仅仅做了重定向的处理 InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders()); // 回调 callback.onDataReady() 方法将结果回传 // callback 是在调用方法时传递过来的,这里即 SourceGenerator#startNext() 方法中传递的,即 SourceGenerator 对象自身 callback.onDataReady(result); } catch (IOException e) {
callback.onLoadFailed(e); } finally {
... }}

数据加载的过程也是很简单的, HttpUrlFetcher 它使用了 HttpURLConnection 发起了网络请求, 获取了数据流, 至此数据资源的获取就已经完成了, 后面要做的便是最重要的数据处理了, 它通过回调的方式将 InputStream 类型的结果一步一步的进行回调, 最终会回溯到 DecodeJob#onDataFetcherReady 这个方法中。

具体的回调流程,参见:

然后,后续的对于原始数据资源的处理,参见: 。(由于时间与篇幅原因,暂时不单独进行后续分析)


相关内容索引:

(1)
(2)
(3)


主要参考文章:

1、(郭神的博客,基于 3.7.0 分析的)
2、
3、

转载地址:http://urerj.baihongyu.com/

你可能感兴趣的文章
Leetcode 442. 数组中重复的数据
查看>>
PAT (Advanced Level) Practice 1147 Heaps (30 分)堆
查看>>
PAT (Advanced Level) Practice 1146 Topological Order (25 分) 拓扑排序
查看>>
PAT (Advanced Level) Practice 1149 Dangerous Goods Packaging (25 分)set
查看>>
PAT (Advanced Level) Practice 1001 A+B Format (20 分)
查看>>
PAT (Advanced Level) Practice 1021 Deepest Root (25 分)
查看>>
数据结构 顺序表 操作集
查看>>
PAT (Advanced Level) Practice 1040 Longest Symmetric String (25 分) 最长回文字符串 dp
查看>>
PAT (Advanced Level) Practice 1142 Maximal Clique (25 分) 暴力
查看>>
HDU 数塔 dp
查看>>
AOJ 0-1 Knapsack Problem 01背包 dp
查看>>
Aizu - DPL_1_D Longest Increasing Subsequence dp+二分查找 最长递增子序列
查看>>
nyoj 10-skiing dp
查看>>
nyoj 49-开心的小明 dp
查看>>
nyoj 15-括号匹配(二) 模拟
查看>>
nyoj 104-最大和
查看>>
HDU 2045 不容易系列之(3)—— LELE的RPG难题
查看>>
HDU 2047 阿牛的EOF牛肉串 递推
查看>>
HDU 2048 神、上帝以及老天爷 错排公式
查看>>
HDU 2049 不容易系列之(4)——考新郎
查看>>