Glide图片加载流程源码解析
- Glide图片加载流程源码解析
- Glide介绍与优势
- Glide整体运转流程
- with()
- with()工作小结
- load()
- load工作小结
- into()
- 流程
- 创建ViewTarget对象
- 创建MAIN_THREAD_EXECUTOR
- 执行重载的into方法
- 构建网络请求对象Request
- 执行网络请求对象Request
- 加载前
- 加载时
- SingleRequest.begin()
- URL为空,调用onLoadFailed()
- ImageViewTarget.onloadFailed()
- URL不为空,调用SingleRequest.onLoadStarted()
- ImageViewTarget.onLoadStarted()
- onSizeReady()
- 构建任务 Engine.load
- 执行任务 EngineJob.start()
- DecodeJob.run
- SourceGenerator.startNext()
- 获取数据加载器
- DecodeHelper.getLoadData()
- StringLoader.StreamFactory()
- HttpUriLoader.Factory.build
- HttpGlideUrlLoader.Factory.build()
- StringLoader.StringLoader构造器
- StringLoader.buildLoadData()
- HttpGlideUrlLoader
- SourceGenerator.startNext()
- 执行数据加载 HttpUrlFetcher.loadData()
- 返回数据
- SourceGenerator.onDataReady()
- DecodeJob.onDataFetcherReady
- 解析数据
- 在主线程中显示图片
- DecodeJob
- 回调数据
- Engine.load
- EngineJob.onResourceReady
- 回到主线程
- ResourceCallbackAndExecutor
- EngineJob
- Engine.load()
- SingleRequest.onSizeReady()
- EngineJob.onResourceReady()
- Executors.mainThreadExecutor()
- 显示图片
- EngineJob.CallResourceReady.run()
- SingleRequest.onResourceReady()
- ImageViewTarget
- DrawableImageViewTarget.setResource()
- 小结
- 总结
- 参考文献
Glide图片加载流程源码解析
Glide介绍与优势
Glide是什么
Glide是Google在2014的IO大会发布的一款图片处理框架,是目前android领域比较成熟的一款,也是Google官方推荐的图片处理框架,主要支持网络图片、二进制流、drawable资源、本地图片显示,还支持本地视频显示。
功能
优势
- 多种图片格式的缓存,适用于更多的内容表现形式(如Gif、WebP、缩略图、Video)
- 生命周期集成(根据Activity或者Fragment的生命周期管理图片加载请求)
- 高效处理Bitmap(bitmap的复用和主动回收,减少系统回收压力)
- 高效的缓存策略,灵活、加载速度快且内存开销小(默认Bitmap格式的不同,使得内存开销小)
应用场景
- 需要更多的内容表现形式(如Gif)
- 更高的性能要求(缓存 & 加载速度)
Glide整体运转流程
with()
-
定义:Glide类中的静态方法,根据传入的参数不同进行方法重载
-
作用:
- 得到一个RequestManager对象
- 预先创建好对图片进行一系列操作(加载,编解码,转码)的对象,并添加到Glide的注册表registry中
- 根据传入with()方法的参数将Glide图片加载的生命周期与Activity/Fragment的生命周期进行绑定,从而实现自动执行请求、暂停操作
-
介绍之前介绍几个重要的对象名:
- RequestManagerFragment:连接生命周期方法
- RequestManager:其实现了LifeCycleListener接口,用来绑定Activity/Fragment生命周期,实现生命周期中的请求方法
- RequestManagerRetriever:将RequestFragment和自定义Fragment(如RequestManagerFragment)绑定,从而实现在生命周期管理回调
流程
with的重载
Glide.with()方法会根据传入的参数不同进行方法重载:
/**
* Application类型
*/
public static RequestManager with(@NonNull Context context) {
//getRetriever会返回RequestManagerRetriever的单例对象
//RequestManagerRetriever的get会返回RequestManager对象并绑定图片加载的生命周期
return getRetriever(context).get(context);
}
/**
* 非Application类型
*/
public static RequestManager with(@NonNull Activity activity) {
//跟Application类型一样会调用RequestManagerRetriever的get获取RequestManager对象
//不过需注意在这里传递的参数为Activity
return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
我们发现,无论传入参数是什么类型,都会调用getRetriever方法去创造返回一个RequestManagerRetriever的单例对象,然后调用这个对象的get方法返回一个RequestManager对象并绑定图片加载的生命周期。
getRetriever()获取RequestManagerRetriever对象
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
...
//1.调用Glide.get获取到Glide的对象,Glide对象中封装了RequestManagerRetriever对象
//2.通过Glide的getRequestManagerRetriever()获取到RequestManagerRetriever对象
return Glide.get(context).getRequestManagerRetriever();
}
- 此方法是先根据参数获取Glide对象,然后根据Glide对象的getRequestManagerRetriever()方法获取到RequestManagerRetriever。
Glide.get(context)
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
//重点关注
checkAndInitializeGlide(context);
}
}
}
return glide;
}
private static void checkAndInitializeGlide(@NonNull Context context) {
if (isInitializing) {
//如果同时进行两次初始化会抛出该异常
throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
+ " use the provided Glide instance instead");
}
isInitializing = true;
//进行初始化操作
initializeGlide(context);
isInitializing = false;
}
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
....
//构造Glide的实体对象,此时的builder为GlideBuilder
Glide glide = builder.build(applicationContext);
....
}
- get方法中对Glide类上锁,然后调用checkAndInitializeGlide方法进行初始化的检查以及初始化,如果同时进行了两次初始化就会抛出异常,否则调用initializeGlide初始化Glide实体对象,最后则是在initializeGlide方法中通过GlideBuilder的build来构造Glide的实体对象,下面我们看一下GlideBuilder的build方法是如何来构建的。
build()
@NonNull
Glide build(@NonNull Context context) {
......
//构建管理线程池与缓存的执行引擎
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor(),
isActiveResourceRetentionAllowed);
}
//构建了一个RequestManagerRetriever对象
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
//构建Glide对象,并将上面的众多线程池和RequestManagerRetriever对象封装进去
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions,
defaultRequestListeners,
isLoggingRequestOriginsEnabled);
}
}
public class Glide implements ComponentCallbacks2 {
Glide(
@NonNull Context context,
@NonNull Engine engine,
@NonNull MemoryCache memoryCache,
@NonNull BitmapPool bitmapPool,
@NonNull ArrayPool arrayPool,
@NonNull RequestManagerRetriever requestManagerRetriever,
@NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
int logLevel,
@NonNull RequestOptions defaultRequestOptions,
@NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
@NonNull List<RequestListener<Object>> defaultRequestListeners,
boolean isLoggingRequestOriginsEnabled) {
...
//将RequestManagerRetriever对象赋值到成员变量中
this.requestManagerRetriever = requestManagerRetriever;
....
//解码器
StreamBitmapDecoder streamBitmapDecoder = new StreamBitmapDecoder(downsampler, arrayPool);
//添加到注册表中
registry
.append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder)
....
/* Models */
//重点关注InputStreamRewinder
.register(new InputStreamRewinder.Factory(arrayPool))
....
//重点关注StringLoader.StreamFactory()
.append(String.class, InputStream.class, new StringLoader.StreamFactory())
....
//重点关注HttpUriLoader.Factory()
.append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
....
//重点关注HttpGlideUrlLoader
.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
....
/* Transcoders */
//重点关注BitmapDrawableTranscoder
.register(
Bitmap.class,
BitmapDrawable.class,
new BitmapDrawableTranscoder(resources))
.....
}
}
- 总结一下build方法就是创建一个RequestManagerRetriever对象,创建管理线程池与缓存的执行引擎Engine对象,然后在最后new出Glide对象时,在Glide构造方法中又构建了registry注册表,在这里面注册了众多的编解码器。至此我们就已经创建完了一个Glide对象,并且将RequestManagerRetriever对象赋值给了Glide的成员变量,接下来就可以调用其的getRequestManagerRetriever方法获取到这个RequestManagerRetriever对象了。
在最初的with方法中,我们知道我们要获取RequestManagerRetriever对象,然后调用其get方法获取RequestManager对象。
RequestManagerRetriever.get()获取RequestManager对象
这个get方法和Glide的with方法一样根据不同的参数传入有很多重载方法,大致分为Application类型和非Application类型两种
1.获取Applicaition类型的RequestManager对象
//Application类型
public RequestManager get(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
//若在主线程且context不为Application类型
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
//若不在主线程或者为Application类型的调用getApplicationManager获取一个RequestManager对象
return getApplicationManager(context);
}
接着调用getApplicationManager方法
private RequestManager getApplicationManager(@NonNull Context context) {
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
//get方法为获取Glide的单例对象,
//由于上面已经创建好Glide的单例对象了,所以在这里就直接取Glide的单例对象不需创建
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
public interface RequestManagerFactory {
@NonNull
RequestManager build(
@NonNull Glide glide,
@NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode requestManagerTreeNode,
@NonNull Context context);
}
private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() {
@NonNull
@Override
public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) {
return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
}
};
}
在这个方法中,会先获取之前创造的Glide对象,然后new出一个ApplicationLifecycle对象传入applicationManager的build中创建RequestManager对象从而实现RequestManager与Application生命周期的绑定,至此也就实现了Glide和Application的生命周期绑定。
2.获取非Application类型的RequestManager对象
这里我们就以activity为例,因为其他非Application类型的处理与activity基本是类似的。
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
//如果在子线程则直接调用Aplication类型的get
return get(activity.getApplicationContext());
} else {
//判断Activity是否销毁
assertNotDestroyed(activity);
//获取FragmentManager对象
FragmentManager fm = activity.getSupportFragmentManager();
//通过调用supportFragmentGet返回RequestManager
return supportFragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
首先要判断这个请求是在主线程中还是子线程中,如果是子线程中就调用Application类型的get方法。因为在子线程中Glide的生命周期应该与Application的生命周期相一致。如果是在主线程中,就调用supportFragmentGet方法来跟Activity的生命周期绑定。
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
//获取SupportRequestManagerFragment
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
//实现创建,添加Fragment
RequestManager requestManager = current.getRequestManager();
//如果首次加载则初始化requestManager
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
//设置到SupportRequestManagerFragment中
current.setRequestManager(requestManager);
}
return requestManager;
}
在这个方法里,创建了一个无UI的隐藏的Fragment,将其添加到当前activity中,然后创建RequestManager对象传入Glide对象,和Fragment的生命周期从而实现RequestManager与Fragment的生命周期进行绑定,进而与Activity的生命周期进行了绑定。
with()工作小结
获取RequestManagerRetriever对象,然后调用其get方法获取RequestManager对象并返回。
在获取RequestManagerRetriever对象的过程中,创建了Glide的对象,在Glide的构造中,创建管理线程池与缓存的执行引擎Engine对象、构建了Registry注册表,注册了许多的编解码器、构建了RequestManagerRetriever。至此获取到了RequestManagerRetriever对象,在调用get方法获取RequestManager对象的过程中,如果是在子线程中或者with参数为Application类型,则直接在创建RequestManager的过程中,传入glide和application的lifecycle使Glide图片加载的生命周期与Application的生命周期绑定。否则,则要创建一个隐藏的Fragment添加到Activity中,然后在创建RequestManager的过程中,传入glide和fragment的声明周期,由于fragment的生命周期与activity的生命周期相同,则使Glide图片加载的生命周期间接的与Activity的生命周期绑定。
load()
- load方法传入一个需要加载的资源(String、URL、URI等等),创建一个目标为Drawable的图片加载请求。
流程
对于刚刚with的分析,我们with方法最终会返回一个RequestManager对象,所以load方法就是调用的是RequestManager的load方法
RequestManager.load()方法
load方法在RequestManager中根据参数的不同,也是有很多重载方法的
public RequestBuilder<Drawable> load(@Nullable String string) {
//1.asDrawable创建一个目标为Drawable的图片加载请求
//2.调用load将加载的资源传入
return asDrawable().load(string);
}
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
public RequestBuilder<Drawable> load(@Nullable URL url) {
return asDrawable().load(url);
}
看到load有很多重载方法,但我们下面只分析最常见的加载图片的load参数,即load(String url)。
首先调用了asDrawable()方法
asDrawable()
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
- 这个代码很简单,就是创建一个目标为Drawable的图片加载请求RequestBuilder。
返回RequestBuilder后,则调用了其load方法
RequestBuilder.load()
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
//将数据赋值给RequestBuilder的静态成员变量
this.model = model;
isModelSet = true;
return this;
}
这个load方法调用了loadGeneric方法,将数据String类型的model赋值给RequestBuilder的静态成员变量model,然后将isModelSet变量设置为true。
load工作小结
load()方法的工作首先就是创建一个目标为Drawable的图片加载请求RequestBuilder,然后调用其load方法,进而调用loadGeneric方法将传入的Stirng类型的url赋值给静态变量model。在3.x的源码中load本来还应该完成一项任务,即预先创建好对图片进行一系列操作(加载,编解码,转码)的对象。而通过上述对with的分析,我们知道在4.9的源码中,这项工作已经交给with来处理了,所以load相比较其它两个来说,其工作是比较简单的。
into()
- 作用:在子线程中网络请求解析图片,并回到主线程中展示图片
流程
下面的源码讲解,基于load参数为String,不采取内存缓存、磁盘缓存的情况
通过上面的讲解我们知道,load方法返回的是一个RequestBuilder对象,所以into方法调用的是RequestBuilder的into方法
RequestBuilder.into(view)
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
.....
//返回ViewTarget对象
return into(
//glideContext为GlideContext类型
glideContext.buildImageViewTarget(view, transcodeClass),
targetListener = null,
requestOptions,
//含有绑定主线程Handler的线程池
Executors.mainThreadExecutor());
}
- 在这里,我们会先获取一些传入into方法的参数,一个是ViewTarget对象,一个是线程池。我们先关注一下如何创建一个ViewTarget对象
创建ViewTarget对象
GlideContext.buildImageViewTarget
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
这里继续调用imageViewTatgetFactory的buildTarget方法,传入view和transcodeClass(也就是我们load方法中的Drawable.class)
ImageViewTargetFactory.buildTarget
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
@NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
//若是调用了asBitmap方法
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)");
}
}
由于我们在load流程中,使用的是asDrawable方法,所以这一步会返回一个DrawableImageViewTarget(又称target),这个对象在后续展示图片时将会用到。
创建MAIN_THREAD_EXECUTOR
在into方法中,我们还要创建一个含有绑定主线程Handler的线程池,调用的是Executors.mainThreadExecutor()方法
Executors.mainThreadExecutor()
public static Executor mainThreadExecutor() {
return MAIN_THREAD_EXECUTOR;
}
private static final Executor MAIN_THREAD_EXECUTOR =
new Executor() {
//绑定主线程的Looper
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(@NonNull Runnable command) {
handler.post(command);
}
};
- 这个方法中,返回的就是MAIN_THREAD_EXECUTOR。而我们看见MAIN_THREAD_EXECUTOR中声明了一个绑定主线程Looper的Handler。然后这个线程池的execute方法会执行Handler的post方法,相当于在主线程中执行command的run方法,这个后面会讲到,在这里先说一下了解。
执行重载的into方法
在分析完into的两个重要参数之后,接下来就看一下这个重载的into方法做了什么?
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()");
}
//构建Requset对象,发出加载图片请求
//注意第四个参数传进去的是含有绑定主线程的Handler的线程池
Request request = buildRequest(target, targetListener, options, callbackExecutor);
//在开始前先释放掉target对象已存在的请求
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
requestManager.clear(target);
//将请求设置到target中
target.setRequest(request);
//分发并执行网络请求Request,此时的requestManager就是
requestManager.track(target, request);
return target;
}
- 在这里首先根据传入的参数去创建一个网络Request对象,然后释放掉target中已存在的request,把新的Request存放到放到target中,然后将调用requestManager的track方法传入target和request请求进行分发并执行网络请求。
说白了主要的工作就是两个:一是构建网络请求的Request,二是执行网络请求对象Request,接下来我们就分别对这两个工作进行分析。
构建网络请求对象Request
调用的是buildRequest方法
RequestBuilder.buildRequest()
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
//重点关注buildRequestRecursive方法
return buildRequestRecursive(
target,
targetListener,
parentCoordinator = null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
调用了buildRequestRecursive()方法
buildRequestRecursive()
private Request buildRequestRecursive(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
.....
//重点关注buildThumbnailRequestRecursive方法
Request mainRequest =
buildThumbnailRequestRecursive(
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
if (errorRequestCoordinator == null) {
return mainRequest;
}
......
}
调用buildThumbnailRequestRecursive()方法
buildThumbnailRequestRecursive()
private Request buildThumbnailRequestRecursive(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
....
//重点关注,关键代码
Request fullRequest =
obtainRequest(
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
........
}
调用了obtainRequest()方法
obtainRequest()
private Request obtainRequest(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
//调用了SingleRequest的obtain方法,将load中调用的所有API参数都组装到Request对象当中
//此时的callbackExecutor为含有绑定主线程Handler的线程池
return SingleRequest.obtain(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
经过一步一步的调用,最后会执行SingleRequest的obtain方法,所以我们继续看这个方法
SingleRequest.obtain()方法
public static <R> SingleRequest<R> obtain(
Context context,
GlideContext glideContext,
Object model,
Class<R> transcodeClass,
BaseRequestOptions<?> requestOptions,
int overrideWidth,
int overrideHeight,
Priority priority,
Target<R> target,
RequestListener<R> targetListener,
@Nullable List<RequestListener<R>> requestListeners,
RequestCoordinator requestCoordinator,
Engine engine,
TransitionFactory<? super R> animationFactory,
Executor callbackExecutor) {
@SuppressWarnings("unchecked") SingleRequest<R> request =
(SingleRequest<R>) POOL.acquire();
if (request == null) {
//创建SingleRequest对象
request = new SingleRequest<>();
}
//将传入load中的API参数赋值到SingleRequest的成员变量
//最后一个参数为主线程的线程池
request.init(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
engine,
animationFactory,
callbackExecutor);
return request;
}
- 这个obtain方法就是创建一个SingleRequest对象,然后调用init方法对其进行成员变量的赋值,这一步就把load过程中的所有API参数(比如加载时的站位图)都添加到这个网络请求对象SingleRequest中了。至此完成了创建网络请求对象SingleRequest。
执行网络请求对象Request
我们记得在into方法中,构建出网络请求对象后,调用了RequestManager的track方法进行分发并执行这个请求。
加载前
RequestManager.track()
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
//执行网络请求
requestTracker.runRequest(request);
}
这个方法里面调用了requestTracker的runRequest方法去执行网络请求
RequestTracker.runRequest
public void runRequest(@NonNull Request request) {
//将每个提交的请求加入到一个set中,从而实现管理请求
requests.add(request);
//判断Glide当前是否处于暂停状态
if (!isPaused) {
//如果不暂停,则调用SingleRequest的begin方法来执行request
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
//如果暂停,则先将当前的请求添加到待执行队列里面,等待暂停状态解除后再执行
pendingRequests.add(request);
}
}
- 在加载图片前,即开始网络请求之前,我们需要把每个request请求加到set中来进行管理请求,并且还需要判断Glide当前的状态,如果不是暂停状态,则执行SingleRequest的begin方法,这里的Request就是SingleRequest对象。
加载时
加载时就要用到SingleRequest的begin方法了
SingleRequest.begin()
public synchronized void begin() {
....
//model为load传入的图片URL地址
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
//如果传入的URL地址为空,则会调用onLoadFailed
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
status = Status.WAITING_FOR_SIZE;
//图片加载有两种情况:
//1.使用了override()的API为图片指定了固定宽高
//2.无使用
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
//指定了宽高的话调用onSizeReady加载
onSizeReady(overrideWidth, overrideHeight);
} else {
 //getsize计算宽高,然后执行onSizeReady方法,
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
//在图片请求成功前,会先使用Loading占位图代替最终的图片显示
target.onLoadStarted(getPlaceholderDrawable());
}
.....
}
- 这个方法中,会判断传入的图片URL地址是否为空,如果为空调用onLoadFailed方法,如果不为空则先用onSizeReady方法加载宽高数据,然后调用target.onLoadStarted方法。注:在图片请求成功前,会先使用loading占位图代替最终的图片显示。
URL为空,调用onLoadFailed()
private synchronized void onLoadFailed(GlideException e, int maxLogLevel) {
.....
loadStatus = null;
status = Status.FAILED;
isCallingCallbacks = true;
try {
boolean anyListenerHandledUpdatingTarget = false;
if (requestListeners != null) {
for (RequestListener<R> listener : requestListeners) {
anyListenerHandledUpdatingTarget |=
listener.onLoadFailed(e, model, target, isFirstReadyResource());
}
}
anyListenerHandledUpdatingTarget |=
targetListener != null
&& targetListener.onLoadFailed(e, model, target, isFirstReadyResource());
if (!anyListenerHandledUpdatingTarget) {
//重点关注这个方法
setErrorPlaceholder();
}
} finally {
isCallingCallbacks = false;
}
notifyLoadFailed();
}
private synchronized void setErrorPlaceholder() {
if (!canNotifyStatusChanged()) {
return;
}
Drawable error = null;
//先获取fallback的图片
if (model == null) {
error = getFallbackDrawable();
}
//若没有设置fallback图,则获取error图
if (error == null) {
error = getErrorDrawable();
}
//若没有error图,则再获取一个loading的占位图
if (error == null) {
error = getPlaceholderDrawable();
}
//target为DrawableImageViewTarget
target.onLoadFailed(error);
}
- 在这个onLoadFailed方法中,我们只需要关注setErrorPlaceholder方法,而在setErrorPlaceholder中主要的逻辑就是获取错误时需要展示的图片,按fallback>error>loading的优先级来获取错误时的图片,然后调用DrawableImageViewTarget的onLoadFailed方法。我们发现这个类中并没有onLoadFailed方法,而它的父类ImageViewTarget存在这个方法,我们看一下
ImageViewTarget.onloadFailed()
public void onLoadFailed(@Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
setResourceInternal(null);
//调用setDrawable将图片显示出来
setDrawable(errorDrawable);
}
public void setDrawable(Drawable drawable) {
//view就是ImageView,将图片展示出来
view.setImageDrawable(drawable);
}
在这个方法中,通过调用setDrawable方法将表示错误的图片显示出来。也就是说Glide显示错误图片的原则就是:当传入图片的url为null时,会采用fallback/error/loading的优先级顺序来获取占位图进行代替。
URL不为空,调用SingleRequest.onLoadStarted()
以下是SingleRequest.onLoadStarted()相关的代码
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
//在图片请求成功前,会先使用Loading占位图代替最终的图片显示
target.onLoadStarted(getPlaceholderDrawable());
}
- 这个方法中,就是当图片正在请求时或者等待执行onSizeReady方法时,就执行DrawableImageViewTarget的onLoadStarted方法,由onLoadFailed方法的分析,我们知道调用的实际上是其父类ImageViewTarget的onLoadStarted方法,参数就是loading的占位图。
ImageViewTarget.onLoadStarted()
public void onLoadStarted(@Nullable Drawable placeholder) {
super.onLoadStarted(placeholder);
setResourceInternal(null);
//在图片请求开始前,会先使用Loading占位图代替最终的图片显示
setDrawable(placeholder);
}
public void setDrawable(Drawable drawable) {
//将图片展示出来
view.setImageDrawable(drawable);
}
- 这个方法就是将loading的占位图显示出来,即图片请求成功前,会先使用Loading占位图代替最终的图片显示。
onSizeReady()
在begin方法中我们说过,无论是否指定宽高,最后都要调用onSizeReady方法,所以我们在这里只分析onSizeReady方法。
@Override
public synchronized void onSizeReady(int width, int height) {
....
status = Status.RUNNING;
loadStatus =
//重点关注,调用Engine的load构建任务
//重点关注倒数第二个参数,传入自身SingleRequest,在回调的时候会使用
//重点关注倒数第一个参数,传入有绑定主线程的Handler的线程池callbackExectuter
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);
}
- onSizeReady方法的实现最终交给了engine的load方法实现,这个engine对象就是在with中Glide构建的执行引擎。
构建任务 Engine.load
public 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) {
.....
//从缓存中查找key对应的任务
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);
}
//走到这,说明这是个新任务
//创建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);
//添加到任务缓存中
jobs.put(key, engineJob);
//现在可以不看
//在获取数据回调进行照片展示时会重新分析到这个方法
engineJob.addCallback(cb, callbackExecutor);
//执行任务
engineJob.start(decodeJob);
...
return new LoadStatus(cb, engineJob);
}
- 这个方法中主要的工作是创建一个EngineJob对象用来开启线程,然后创建一个DecodeJob对象,用来对图片进行解码,将任务添加到任务缓存中,将回调添加到EngineJob中,然后调用其start()方法进行任务的执行。
执行任务 EngineJob.start()
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
//获取线程池
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
//执行DecodeJob的run方法
executor.execute(decodeJob);
}
在这里面获取线程池,调用线程池的execute方法,故接下来会执行DecodeJob的run方法
DecodeJob.run
public void run() {
....
try {
if (isCancelled) {
notifyFailed();
return;
}
//重点关注,调用runWrapped
runWrapped();
}
....
}
private 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);
}
}
//获取任务场景
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
//若配置的缓存策略允许从资源缓存中读取数据,则返回Stage.RESOURCE_CACHE
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
//若配置的缓存策略允许从源数据缓存读取数据,则返回Stage.DATA_CACHE
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
//若只能允许从缓存中读取数据,则直接FINISH,否则返回Stage.SOURCE,表示加载新的资源
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:
// 资源磁盘缓存的执行者
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;
// 调用 DataFetcherGenerator.startNext() 执行了请求操作
//我们这里主要分析的是无缓存情况,所以这里的DataFetcherGenerator应该是SourceGenerator
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
.....
}
在这个执行任务的方法中,大致分为3个步骤:
- 获取任务场景
- 获取任务场景的执行者
- 执行者执行任务
场景和执行者是一一对应的,由于我们现在分析的是第一次加载图片,并且没有配置缓存策略,所以对应的任务场景为无缓存情况,与之相对应的执行者就是SourceGenerator对象,所以当执行任务时调用的是SourceGenerator的startNext方法
SourceGenerator.startNext()
public boolean startNext() {
......
boolean started = false;
while (!started && hasNextModelLoader()) {
//从DecodeHelper的数据加载集合中, 获取一个数据加载器
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
//使用加载器fetcher执行数据加载
//此fetcher为HttpUrlFetcher对象
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
获取数据加载器
首先看一下如何得到数据加载器的集合
DecodeHelper.getLoadData()
List<LoadData<?>> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
//从Glide注册的register中获取modelLoaders
List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
//遍历modelLoaders
for (int i = 0, size = modelLoaders.size(); i < size; i++) {
//此时分析的model为url的string格式,该其中一个实现类为StringLoader
ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
//通过StringLoader构造loadData
//经过Glide的registry分析后最终会执行HttpGlideUrlLoader的buildLoadData方法
//最终的loadData封装了HttpUrlFetcher对象
LoadData<?> current =
modelLoader.buildLoadData(model, width, height, options);
if (current != null) {
//添加到loadData集合中
loadData.add(current);
}
}
}
//最终返回的是含有HttpUrlFetcher对象的loadData集合
return loadData;
}
- 这个方法首先需要从Glide注册的registry中获取modelLoaders,因为我们全文以String为例子,所以这里的model是String类型的
注:在注册表中注册的都是ModelLoader的实现ModelLoaderFactory静态工厂类,当调用Registry的getModelLoaders方法是会调用工厂类中的build方法,现在我们需要回头看看Glide构建时的注册表,看看model为String类型时有那些ModelLoader的静态工厂类,下面只列举几个:
registry
//重点关注StringLoader.StreamFactory()
.append(String.class, InputStream.class, new StringLoader.StreamFactory())
.append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
.append(
String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory())
下面我们以StringLoader.StreamFactory为例子,由于调用了getModelLoaders方法,所以会执行StringLoader.StreamFactory的build方法。
StringLoader.StreamFactory()
public static class StreamFactory implements ModelLoaderFactory<String, InputStream> {
@NonNull
@Override
public ModelLoader<String, InputStream> build(
@NonNull MultiModelLoaderFactory multiFactory) {
//从Glide的registry的models注册表可以得知
//这时候的multiFactory为HttpUriLoader.Factory()
//不断追踪下去得知最终参数里返回的是HttpGlideUrlLoader对象
return new StringLoader<>(multiFactory.build(Uri.class, InputStream.class));
}
.....
}
- 从build方法中,构建了StringLoader对象,但是其中的参数又调用了另外一个MultiModelLoaderFactory,这时候我们需要看会Glide的注册表中,然后找到参数为Uri.class, InputStream.class时构建的MultiModelLoaderFactory对象
Glide#Glide的构造器
registry
//重点关注HttpUriLoader.Factory()
.append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
可以发现这时候的MultiModelLoaderFactory对象将会是HttpUriLoader.Factory()类型的,所以我们还需要看看其中的build方法
HttpUriLoader.Factory.build
public ModelLoader<Uri, InputStream> build(MultiModelLoaderFactory multiFactory) {
//根据Glide中的registry中的Models注册表可以知道
//这时候的multiFactory为HttpGlideUrlLoader.Factory()
return new HttpUriLoader(multiFactory.build(GlideUrl.class, InputStream.class));
}
还是跟上面一样的步骤,继续查看Glide的注册表,找出参数为GlideUrl.class, InputStream.class的MultiModelLoaderFactory对象
registry
//重点关注HttpGlideUrlLoader
.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
再看看HttpGlideUrlLoader.Factory的build方法
HttpGlideUrlLoader.Factory.build()
public ModelLoader<GlideUrl, InputStream> build(MultiModelLoaderFactory multiFactory) {
//最终返回的是HttpGlideUrlLoader对象
return new HttpGlideUrlLoader(modelCache);
}
这里的build方法返回的是HttpGlideUrlLoader类型,所以最终构建StringLoader对象中的参数将是HttpGlideUrlLoader类型的。于是我们看看StringLoader的构造器的实现。
StringLoader.StringLoader构造器
public StringLoader(ModelLoader<Uri, Data> uriLoader) {
//此时的uriLoader为HttpGlideUrlLoader对象,赋值给静态成员变量
this.uriLoader = uriLoader;
}
构建器就是简单的给成员变量赋值,此时的uriLoader为HttpGlideUrlLoader对象。这就是getModelLoaders所做的事,我们继续分析DecodeHelper的getLoadData方法,当获取到了String的modelLoaders后会遍历每一个modelLoader,然后调用modelLoader的buildLoadData来构造loadData对象,这里我们直接用上面分析得到的StringLoader为例,让我们看看StringLoader的buildLoadData的实现
StringLoader.buildLoadData()
public LoadData<Data> buildLoadData(@NonNull String model, int width, int height,
@NonNull Options options) {
Uri uri = parseUri(model);
if (uri == null || !uriLoader.handles(uri)) {
return null;
}
//此时的uriLoader为HttpGlideUrlLoader对象
return uriLoader.buildLoadData(uri, width, height, options);
}
由上面分析我们已经知道此时StringLoader中的uriLoader为HttpGlideUrlLoader对象,所以会继续调用HttpGlideUrlLoader的buildLoadData方法
HttpGlideUrlLoader
public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height,
@NonNull Options options) {
// GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time
// spent parsing urls.
GlideUrl url = model;
if (modelCache != null) {
url = modelCache.get(model, 0, 0);
if (url == null) {
modelCache.put(model, 0, 0, model);
url = model;
}
}
int timeout = options.get(TIMEOUT);
//创建了一个LoadData对象, 并且封装了HttpUrlFetcher对象
return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}
其它代码我们并不需要过多的关注,只需要关注最后的返回值,可以发现最后返回的是封装了HttpUrlFetcher的LoadData对象,这样getLoadData方法获取到的就是封装了HttpUrlFetcher的LoadData对象。让我们回到SourceGenerator的startNext方法。
SourceGenerator.startNext()
public boolean startNext() {
......
boolean started = false;
while (!started && hasNextModelLoader()) {
//最终获取的的对象就是封装了HttpUrlFetcher的LoadData对象
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
//使用加载器fetcher执行数据加载
//此fetcher为HttpUrlFetcher对象
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
上面已经分析了loadData是封装了HttpUrlFetcher的LoadData对象,所以执行数据加载其实就是调用了HttpUrlFetcher的loadData方法。
执行数据加载 HttpUrlFetcher.loadData()
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());
//将inputStream回调出去,callback为DataCallback
callback.onDataReady(result);
}
......
}
//网络请求代码,利用了HttpURLConnection进行网络请求
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
Map<String, String> headers) throws IOException {
......
//静态工厂模式创建HttpUrlConnection对象
urlConnection = connectionFactory.build(url);
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
//设置连接超时时间为2500ms
urlConnection.setConnectTimeout(timeout);
//设置读取超时时间为2500ms
urlConnection.setReadTimeout(timeout);
//不使用http缓存
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
// Stop the urlConnection instance of HttpUrlConnection from following redirects so that
// redirects will be handled by recursive calls to this method, loadDataWithRedirects.
urlConnection.setInstanceFollowRedirects(false);
// Connect explicitly to avoid errors in decoders if connection fails.
urlConnection.connect();
// Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
stream = urlConnection.getInputStream();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (isHttpOk(statusCode)) {
//请求成功
return getStreamForSuccessfulRequest(urlConnection);
}
......
}
private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
throws IOException {
if (TextUtils.isEmpty(urlConnection.getContentEncoding())) {
int contentLength = urlConnection.getContentLength();
stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength);
} else {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Got non empty content encoding: " + urlConnection.getContentEncoding());
}
stream = urlConnection.getInputStream();
}
//最终返回的是图片的InputStream对象,还未开始读取数据
return stream;
}
可以发现执行数据加载有两个工作,首先是获取数据的输入流,这里采取的是HttpURLConnection进行网络请求,最终获取到的是数据的InputStream对象,记住这时候并未开始读取数据。
返回数据
当获取到输入流后,还需要将这个输入流返回出去
callback.onDataReady(result);
可以发现这里使用的是回调的方法将数据的输入流回调出去。此时callbak为DataCallback对象,根据回调的使用我们知道下一步应该要找到实现DataCallback接口的类,怎么找呢?这时候就需要往回找,调用loadData方法的是在SourceGenerator的startNext方法,所以我们首选目标就是这个SourceGenerator类
SourceGenerator.onDataReady()
class SourceGenerator implements DataFetcherGenerator,
DataFetcher.DataCallback<Object>,
DataFetcherGenerator.FetcherReadyCallback {
........
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
....
} else {
//继续回调FetcherReadyCallback的onDataFetcherReady方法,将data回调出去
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
}
SourceGenerator类实现了DataFetcher.DataCallback这个接口,并且在这个类找到了onDataReady方法,这个方法还是选择回调,回调了FetcherReadyCallback的onDataFetcherReady方法,于是我们在往回找,并在心中默念:在哪个类中调用了SourceGenerator的startNext方法呢?然后你就会发现是在DecodeJob的run方法中调用了startNext这个方法,然后马上看看DecodeJob是否实现了onDataFetcherReady接口!
DecodeJob.onDataFetcherReady
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback,
Runnable,
Comparable<DecodeJob<?>>,
Poolable {
.......
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
.......
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
//解析获取的数据
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
private void decodeFromRetrievedData() {
....
try {
//获取解析后
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
//通知外界资源获取成功
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
}
由以上分析,onDataFetcherReady方法中主要工作有两件:
- 解析获取的数据
- 返回图片资源
解析数据
DecodeJob
private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data,
DataSource dataSource) throws GlideException {
try {
......
//重点关注decodeFromFetcher方法
Resource<R> result = decodeFromFetcher(data, dataSource);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded result " + result, startTime);
}
return result;
}
......
}
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
throws GlideException {
//获取当前数据类的解析器LoadPath,此时的data为InputStream对象
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);
//此时的data为InputStream对象,故rewinder为InputStreamRewinder对象
DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
try {
//将数据解析转移到LoadPath.load方法中
return path.load(
rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
} finally {
rewinder.cleanup();
}
}
这里的rewinder的获取跟modelLoaders的获取一样需要重新看Glide构建中的注册表registry,在这里不再详细说明,因为data为InputStream对象,所以rewinder为InputStreamRewinder对象,然后调用LoadPath的load方法实现解析数据
LoadPath
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;
//遍历DecodePath集合
for (int i = 0, size = decodePaths.size(); i < size; i++) {
DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i);
try {
//调用DecodePath.decode真正进行数据解析
result = path.decode(rewinder, width, height, options, decodeCallback);
} catch (GlideException e) {
exceptions.add(e);
}
if (result != null) {
break;
}
}
if (result == null) {
throw new GlideException(failureMessage, new ArrayList<>(exceptions));
}
return result;
}
DecodePath
public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
@NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
//获取到Resource<Bitmap>对象
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
//将资源转化为目标效果,如在构建request时设置的CenterCrop
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
//将数据转化为目标格式,将Resource<Bitmap>转换为LazyBitmapDrawableResource对象
//可通过LazyBitmapDrawableResource的get获取到BitmapDrawable对象
//该transcoder为BitmapDrawableTranscoder
return transcoder.transcode(transformed, options);
}
LoadPath的load方法最终会调用DecodePath的decode来解析数据,DecodePath的decode的主要工作就是获取到Resource对象,然后还要将Resource对象转化成LazyBitmapDrawableResource。在这里就不分析如何得到Resource对象,只分析如何将数据转化为目标格式,可以通过Glide构造中的注册表中找出Bitmap转化成Drawable的转化器为BitmapDrawableTranscoder,所以实际上调用了BitmapDrawableTranscoder的transcode来进行转换
BitmapDrawableTranscoder.transcode
public Resource<BitmapDrawable> transcode(@NonNull Resource<Bitmap> toTranscode,
@NonNull Options options) {
//获取LazyBitmapDrawableResource对象
return LazyBitmapDrawableResource.obtain(resources, toTranscode);
}
LazyBitmapDrawableResource
public static Resource<BitmapDrawable> obtain(
@NonNull Resources resources, @Nullable Resource<Bitmap> bitmapResource) {
if (bitmapResource == null) {
return null;
}
//创建了一个LazyBitmapDrawableResource对象
return new LazyBitmapDrawableResource(resources, bitmapResource);
}
public BitmapDrawable get() {
//返回一个BitmapDrawable对象
return new BitmapDrawable(resources, bitmapResource.get());
}
追踪下去可以发现transcode最终会得到一个封装了Resource的对象,然后看LazyBitmapDrawableResource的get方法,可以得到一个BitmapDrawable对象,即目标格式。到这里就成功将数据解析成LazyBitmapDrawableResource对象。
在主线程中显示图片
既然解析完数据,剩下的工作就是将数据显示出来,于是我们得重新看回DecodeJob的decodeFromRetrievedData方法
DecodeJob
private void decodeFromRetrievedData() {
....
try {
//解析成功后resource为封装了Resource<Bitmap>的LazyBitmapDrawableResource对象
//可通过get方法获取到BitmapDrawable对象
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
//通知外界资源获取成功
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
.....
//重点关注
notifyComplete(result, dataSource);
......
}
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
//回调,注意此时的callback为EngineJob(可回头看Engine中DecodeJob的创建)
callback.onResourceReady(resource, dataSource);
}
回调数据
最后又来到了我们熟悉的回调方法,看到这个callback你可能会一脸茫然,这个callback哪个对象呢?
首先先确定下这个notifyComplete是在DecodeJob类中,因此callback应该是其成员变量,然后我们得找出赋值的地方
//重点关注倒数第二个参数,callback的类型为CallBack
DecodeJob<R> init(
GlideContext glideContext,
Object model,
EngineKey loadKey,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
boolean onlyRetrieveFromCache,
Options options,
Callback<R> callback,
int order) {
decodeHelper.init(
glideContext,
model,
signature,
width,
height,
diskCacheStrategy,
resourceClass,
transcodeClass,
priority,
options,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
diskCacheProvider);
this.glideContext = glideContext;
this.signature = signature;
this.priority = priority;
this.loadKey = loadKey;
this.width = width;
this.height = height;
this.diskCacheStrategy = diskCacheStrategy;
this.onlyRetrieveFromCache = onlyRetrieveFromCache;
this.options = options;
this.callback = callback;
this.order = order;
this.runReason = RunReason.INITIALIZE;
this.model = model;
return this;
}
很容易的我们发现在init方法会为callback赋值,这时候得记住callback参数的具体位置为倒数第二个。这时候你会想:哪里会调用DecodeJob的init方法呢?然后揣摩:既然是赋值估计会在构建DecodeJob时候会调用到。最终是会在Engine的load中找到DecodeJob的构建
Engine.load
public synchronized <R> LoadStatus load(....){
//重点关注倒数最后一个参数
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
}
//重点关注最后一个参数
<R> DecodeJob<R> build(GlideContext glideContext,
Object model,
EngineKey loadKey,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
boolean onlyRetrieveFromCache,
Options options,
DecodeJob.Callback<R> callback) {
DecodeJob<R> result = Preconditions.checkNotNull((DecodeJob<R>) pool.acquire());
return result.init(
glideContext,
model,
loadKey,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
callback,
creationOrder++);
}
}
在上面的代码中首先调用了DecodeJobFactory的build方法来构建DecodeJob,DecodeJobFactory是Engine的内部类,然后接着看DecodeJobFactory的build方法,build方法中调用了DecodeJob的init方法,找到callback的值,于是看回build的callback的参数位置,在最后一个,然后往回看Engine的load中调用build的最后一个参数!engineJob!没错最后找到的callback的类型应该是EngineJob类型的,其实EngineJob是实现了DecodeJob.Callback接口的。所以接下来就会回调EngineJob的onResourceReady方法
EngineJob.onResourceReady
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
synchronized (this) {
this.resource = resource;
this.dataSource = dataSource;
}
//重点关注
notifyCallbacksOfResult();
}
void notifyCallbacksOfResult() {
ResourceCallbacksAndExecutors copy;
Key localKey;
EngineResource<?> localResource;
synchronized (this) {
......
//重点关注cbs的类型
//查找cbs里面的类型
copy = cbs.copy();
.....
}
//通知上层Engine的任务完成了
listener.onEngineJobComplete(this, localKey, localResource);
for (final ResourceCallbackAndExecutor entry : copy) {
//回调给ImageViewTarget来展示资源
entry.executor.execute(new CallResourceReady(entry.cb));
}
decrementPendingCallbacks();
}
回到主线程
首先我们先确定EngineJob的onResourceReady方法中最重要的代码片
for (final ResourceCallbackAndExecutor entry : copy) {
//回调给ImageViewTarget来展示资源
entry.executor.execute(new CallResourceReady(entry.cb));
}
在确定分析线程池的execute的方法前,我们需要做的事有:
- 确定entry.executor类型
- 确定entry.cb类型
现在我们知道entry为ResourceCallbackAndExecutor方法,所以我们来看看这个类以及构造器
ResourceCallbackAndExecutor
static final class ResourceCallbackAndExecutor {
final ResourceCallback cb;
final Executor executor;
ResourceCallbackAndExecutor(ResourceCallback cb, Executor executor) {
this.cb = cb;
this.executor = executor;
}
}
可以发现executor和cb都是ResourceCallbackAndExecutor中的成员变量,在构造时被赋值,所以我们需要找到构造ResourceCallbackAndExecutor对象的地方,自然而然我们会锁定上面copy这个变量
EngineJob
final ResourceCallbacksAndExecutors cbs = new ResourceCallbacksAndExecutors();
void notifyCallbacksOfResult() {
ResourceCallbacksAndExecutors copy;
Key localKey;
EngineResource<?> localResource;
synchronized (this) {
......
//重点关注cbs的类型
//查找cbs里面的类型
copy = cbs.copy();
.....
}
.....
}
ResourceCallbacksAndExecutors copy() {
return new ResourceCallbacksAndExecutors(new ArrayList<>(callbacksAndExecutors));
}
//cbs赋值的地方
synchronized void addCallback(final ResourceCallback cb, Executor callbackExecutor) {
stateVerifier.throwIfRecycled();
//此时的cb为singleRequest类型,其实现了ResourceCallback接口
//callbackExecutor就是绑定了主线程Handler的线程池
//cbs的类型为ResourceCallbacksAndExecutors
//add的内部实现就是创建ResourceCallbacksAndExecutor并将cb,callbackExecutor赋值到其成员变量
//然后再add到cbs中
cbs.add(cb, callbackExecutor);
......
}
void add(ResourceCallback cb, Executor executor) {
callbacksAndExecutors.add(new ResourceCallbackAndExecutor(cb, executor));
}
让我们看看copy赋值调用的地方,就是调用了ResourceCallbacksAndExecutors类型的cbs的copy方法,copy其实就是创建了ResourceCallbacksAndExecutor集合,这个集合其实就是cbs,我们还需要找到cbs赋值的地方,你会发现在addCallback方法中会找到cbs的add方法,add方法的内部实现其实就是创建ResourceCallbacksAndExecutor并将cb,callbackExecutor赋值到其成员变量中,所以我们还得确定add方法的两个参数是什么?当初在构建任务时我们有专门提到过这个addCallback方法,让我们重新看看Engine的load方法。
Engine.load()
....
//调用addCallback()注册了一个ResourceCallback
//这里的cb是load方法的倒数第二个参数,load是在singleRequest的onSizeReady()调用的
//查看后cb为singleRequest类型
//重新看回EngineJob的addCallback方法
engineJob.addCallback(cb, callbackExecutor);
//在子线程中执行DecodeJob的run方法
engineJob.start(decodeJob);
要想确定cb和callbackExecutor的类型,我们还需要一步一步往回走
//特别关注最后两个参数
public 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)
SingleRequest.onSizeReady()
loadStatus =
//重点关注倒数第二个参数,传入的是this,即SingleRequest对象,其实现了ResourceCallback接口
//重点关注倒数第一个参数,传入有绑定主线程的Handle的r线程池callbackExectuter
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);
SingleRequest的onSizeReady中我们确定了cb的类型为SingleRequest对象,另外一个参数的话就不一一贴出代码了(都是上文贴过的代码),你可以直接从onSizeReady方法往回看,上面的注释也会提到,最后你会发现这个callbackExecutor其实就是我们一开始提到的含有绑定主线程Handler的线程池。让我们回到最初的地方
EngineJob.onResourceReady()
for (final ResourceCallbackAndExecutor entry : copy) {
//回调给ImageViewTarget来展示资源
//entry.cb为singleRequest类型类型
//entry.executor就是含有绑定了主线程的Handler的线程池,即MAIN_THREAD_EXECUTOR
entry.executor.execute(new CallResourceReady(entry.cb));
}
所以我们来看看Executors的mainThreadExecutor方法
Executors.mainThreadExecutor()
private static final Executor MAIN_THREAD_EXECUTOR =
new Executor() {
//绑定主线程的Looper
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(@NonNull Runnable command) {
handler.post(command);
}
};
public static Executor mainThreadExecutor() {
return MAIN_THREAD_EXECUTOR;
}
根据Handler机制的相关知识,当调用MAIN_THREAD_EXECUTOR的execute方法后将会在主线程中执行CallResourceReady对象的run方法。所以我们看看CallResourceReady的run方法
显示图片
EngineJob.CallResourceReady.run()
public void run() {
synchronized (EngineJob.this) {
if (cbs.contains(cb)) {
// Acquire for this particular callback.
engineResource.acquire();
//重点关注,此时cb为SingleRequest对象
callCallbackOnResourceReady(cb);
removeCallback(cb);
}
decrementPendingCallbacks();
}
}
}
synchronized void callCallbackOnResourceReady(ResourceCallback cb) {
try {
//回调,将目标数据回调出去
//此时的cb为singleRequest类型
cb.onResourceReady(engineResource, dataSource);
} catch (Throwable t) {
throw new CallbackException(t);
}
}
又来到了我们熟悉的回调了,此时的cb是SingleRequest类型,我们已经在上文分析过了。所以会调用SingleRequest的onResourceReady方法
SingleRequest.onResourceReady()
public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
.......
//重点关注
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
//第一次加载
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;
//如果在使用时设置listener的话,就会回调其中的onResourceReady
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为DrawableImageViewTarget
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
//通知加载成功
notifyLoadSuccess();
}
这里我们只需要关注target.onResourceReady(result, animation)这句代码,target对象为DrawableImageViewTarget,所以会调用DrawableImageViewTarget的onResourceReady方法,但是因为DrawableImageViewTarget是没有onResourceReady这个方法的,所以应该是在其父类ImageViewTarget中
ImageViewTarget
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
//是否有动画效果
if (transition == null || !transition.transition(resource, this)) {
//重点关注,静态图
setResourceInternal(resource);
} else {
//gif
maybeUpdateAnimatable(resource);
}
}
private void setResourceInternal(@Nullable Z resource) {
//调用setResource来展示照片
setResource(resource);
maybeUpdateAnimatable(resource);
}
//此方法为抽象方法,由子类实现,由于分析的是静态图,故实现的子类应该为DrawableImageViewTarget
protected abstract void setResource(@Nullable Z resource);
DrawableImageViewTarget.setResource()
protected void setResource(@Nullable Drawable resource) {
//成功展示照片
view.setImageDrawable(resource);
}
到这里调用了setImageDrawable(resource)方法,将图片最终显示出来。到这里我们的Glide的图片加载流程就讲解完了
小结
into方法算的上是整个Glide图片加载流程中逻辑最复杂的方法了,代码量多,相对应的工作量也是超级多的,既要网络获取数据,又要解析并显示数据。
总结
在这里附上以上几个方法的时序图和整理图如下:
参考文献
https://github.com/0xZhangKe/Glide-note
Android主流三方库源码分析(三、深入理解Glide源码)