Glide是Android开发中常用的图片框架,其最基本用法例如Glide.with(context).load(url).into(imageView) ,我们沿着此链式调用的顺序一窥Glide图片加载流程的样貌。
一图胜千言
1.Glide.with(context)
// Glide.java
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getContext()).get(fragment);
}
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
该函数的作用是创建了RequestManager 对象并返回。其参数有五种类型,这里选取Context 类型情形进行分析。
可以看到RequestManager 对象是先通过getRetriver()方法创建得到一个RequestManagerRetriever 对象,再调用该对象的get()方法返回。
1.1RequestManager对象的创建过程
// Glide.java
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// Glide.get(context)获取Glide实例
return Glide.get(context).getRequestManagerRetriever();
}
public static Glide get(@NonNull Context context) {
if (glide == null) {
// 加载AppGlideModule
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
// 加载Mainfest配置、注册模块回调
// 这一步执行了 Glide.build()方法构造Glide实例。build方法下面会讲到
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
在getRetriever(context) 方法中,先通过Glide.get(context) 获取Glide实例,Glide采用双重校验锁的懒汉式的单例模式创建,同时读取AppGlideModule和AndroidManifest.xml的配置。
获取到Glide实例后,紧接着调用getRequestManagerRetriever 方法返回了上一步已经初始化好的RequestManagerRetriever 对象。
1.1.1RequestManagerRetriever 是如何初始化的?
RequestManagerRetriever 对象的初始化主要是在Glide对象的创建过程中完成的,也就是Glide.get(context) 方法中的checkAndInitializeGlide ()函数中,该函数内部调用了Glide.build 方法,源码如下:
// GlideBuilder.java
Glide build(@NonNull Context context) {
// 分配线程池、配置缓存策略
sourceExecutor = GlideExecutor.newSourceExecutor();
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
animationExecutor = GlideExecutor.newAnimationExecutor();
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
// 监听网络变化
connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0) {
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
// engine是负责执行加载任务的
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
animationExecutor,
isActiveResourceRetentionAllowed);
}
if (defaultRequestListeners == null) {
defaultRequestListeners = Collections.emptyList();
} else {
defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
}
// focus 1===
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptionsFactory,
defaultTransitionOptions,
defaultRequestListeners,
isLoggingRequestOriginsEnabled,
isImageDecoderEnabledForBitmaps);
}
注意focus 1处的代码创建了RequestManagerRetriever对象。
public interface RequestManagerFactory {
@NonNull
RequestManager build(
@NonNull Glide glide,
@NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode requestManagerTreeNode,
@NonNull Context context);
}
从以上代码我们可以知道:
1.执行Glide.get()方法时就已经分配好了资源加载、缓存线程池、配置好了缓存策略,这里的engine专门负责加载、解码资源,ConnectivityMonitor注册了网络状态监听器,当网络断开时暂停请求网络资源,重连后继续请求资源; 2.RequestManagerRetriever是通过RequestManagerFactory工厂类构造的,进入到RequestManagerFactory.java类中,可以看到其build()方法获取到了相应的RequestManager对象;
1.1.2 factory.build()方法在什么时候调用的?
在之前getRetriever(context).get(context); 的调用中可以发现 在RequestManagerRetriever类中有一个get()方法,正是在这个方法中调用了factory.build()方法返回了RequestManager对象。
如果Glide.with(context)传入的context参数是Application类 或者是在后台线程调用的该方法,则调用getApplicationManager(Context context)
private RequestManager getApplicationManager(@NonNull Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
// Normally pause/resume is taken care of by the fragment we add to the fragment or
// activity. However, in this case since the manager attached to the application will not
// receive lifecycle events, we must force the manager to start resumed using
// ApplicationLifecycle.
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
否则调用supportFragmentGet 或者fragmentGet
private RequestManager fragmentGet(
@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(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;
}
从这里也可以发现,当App进入后台后会导致页面不可见,此时RequestManager绑定到了ApplicationContext,与App的生命周期一致;在其他情况下,RequestManager是和当前页面的生命周期绑定,因此在RequestManager.java类中也实现了生命周期相关的回调函数;
执行完Glide.with(context)后我们拿到了一个对应的RequestManager对象,接下来就执行下一个任务load(url);
load(url)
拿到了RequestManager,紧接着调用load方法开始执行下一步操作,同样先看看load方法的实现
// RequestManager.java
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);
}
public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return asDrawable().load(resourceId);
}
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);
}
load()同样有多个重载函数,传入的参数可以是图片对象Bitmap、Drawable、本地资源Uri、在线资源路径Url、文件对象File、assets资源的id,这里以参数为Url为例;
asDrawable().load(url) 返回了一个RequestBuilder对象,首先看看asDrawable方法干了什么;
// RequestManager.java
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
asDrawable方法创建了RequestBuilder对象,然后调用RequestBuilder.java中的load方法;
// RequestBuilder.java
// 传入的String类型的url将会被作为缓存的key
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
// 这里返回了自身
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
load函数主要工作就是根据传入的资源类型,构造了一个相应的RequestBuilder对象。至此一切准备工作准备就绪,接下来就是最为重要的一步了-加载、展示文件,让我们来着看into(view)方法如何完成这些任务;
3.load(imageView)
拿到的是对应类型RequestBuilder实例,那么就看看该类里into方法的具体实现。同样into方法有into(@NonNull Y target) 和into(@NonNull ImageView ) 两个重载函数(这两个函数最终都会走到同一个函数中),由于调用into方法时我们传入的参数是ImageView类型的;
// RequestBuilder.java
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
BaseRequestOptions<?> requestOptions = this;
// View's scale type.
// 处理图片缩放,根据缩放类型来初始化对应的requestOptions对象
......
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor() // 运行在主线程的handler ,利用Handler实现子线程到主线程的切换,因为最终将图片设置到ImageView是需要在主线程操作的
);
}
上面代码段首先处理图片缩放类型(裁剪、对齐方式等),并将生成的相关参数放入了requestOptions对象中,然后再将其作为参数传给了RequestBuilder.java类私有方法into。该方法定义的四个参数分别为:viewTarget、target回调监听器、请求参数、主线程的回调函数;
显然外部传入ImageView对象最终被转换成了ViewTarget对象,转换函数便是glideContext.buildImageViewTarget(view, transcodeClass); 无论传入参数是何种类型,最终都会转换成两种类型的ViewTarget :BitmapImageViewTarget 或者DrawableImageViewTarget ;具体取决于asBitmap()、asGif()和asDrawable()函数是否被调用,默认是调用的asDrawable(),所以默认返回的是DrawableImageViewTarget类型。
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {
public DrawableImageViewTarget(ImageView view) {
super(view);
}
/** @deprecated Use {@link #waitForLayout()} instead. */
// Public API.
@SuppressWarnings({"unused", "deprecation"})
@Deprecated
public DrawableImageViewTarget(ImageView view, boolean waitForLayout) {
super(view, waitForLayout);
}
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource); //显示图片
}
}
至此ViewTarget创建完毕,我们再回到RequestBuilder.java私有into方法
// RequestBuilder.java`
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
// 注释1:创建request
Request request = buildRequest(target, targetListener, options, callbackExecutor);
// 获取前一个reqeust请求对象
Request previous = target.getRequest();
// 与上一个请求相同 并且 上一个请求已完成
if (request.isEquivalentTo(previous)&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
// 上一个请求已完成,那么重新启动它
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
// 与上一个请求不同,则清除掉上一个,再将加入新请求
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
顺着代码次序,来看看这个方法每一步都干了什么:
1.首先执行buildRequest方法创建一个新的Request请求req1; 2.获取当前ViewTarget上正在进行中的Request请求req2; 3.判断新建的请求req1与已有的请求req2是否相同,如果相同则判断是否跳过req2请求的缓存,两个条件都满足则开始执行begin()方法开始请求资源并停止往下执行,条件都不满足则继续执行第四步; 4.给ViewTarget设置最新的请求req1,然后执行track方法追踪req1。 5.执行into(view)方法首先获取到了Request请求,然后开始执行Request。如果是复用的Request则直接执行begin(),否则执行track(target, request),但最终仍然会执行begin();
当我们在常见的列表界面中(如 recycleview 实现的列表),使用上面的代码,在我们快速滑动中,glide 是如何实现正确加载图片,而没有导致图片内容的错位或者是不正确呢?
答案就在上面的代码中。执行上面的代码后,glide 要把最新的图片加载到正确的对象上,而取消对象之前关联的图片加载请求。
首先,在该方法中构建了一个 Request 并持有了 target 。这样便可以将结果通知给 target。Target 是 Glide 对我们要加载目标的一个封装和抽象。 判断Taget 中的之前的 Request 和最新构建的 Request 是否相同,如果相同回收最新的 Request ,让旧的 Request 继续运行。如果不同,就取消之前的 Request 和 target 的关联。
requestManager.clear(target);
最终会触发下面的代码
if (!isOwnedByUs && !glide.removeFromManagers(target) && target.getRequest() != null) {
Request request = target.getRequest();
target.setRequest(null);
request.clear();
}
可以看到, target 对应的 request 被置 null, 而旧的 request 被 “clear”。旧的 Request 被 clear 后,又是如何让资源没有去加载到关联的 Target 上的? 我们看其中 SingleRequest 的实现
# SingleRequest.java
/**
* Cancels the current load if it is in progress, clears any resources held onto by the request
* and replaces the loaded resource if the load completed with the placeholder.
*
* <p> Cleared requests can be restarted with a subsequent call to {@link #begin()} </p>
*
* @see #cancel()
*/
@Override
public void clear() {
Util.assertMainThread();
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
if (status == Status.CLEARED) {
return;
}
cancel();
// Resource must be released before canNotifyStatusChanged is called.
if (resource != null) {
releaseResource(resource);
}
if (canNotifyCleared()) {
target.onLoadCleared(getPlaceholderDrawable());
}
// Must be after cancel().
status = Status.CLEARED;
}
可以看到 clear() 方法中先是 执行了 cancel(),该方法会取消加载资源请求与该 Request 的回调关联。
/**
* Cancels the current load but does not release any resources held by the request and continues
* to display the loaded resource if the load completed before the call to cancel.
*
* <p> Cancelled requests can be restarted with a subsequent call to {@link #begin()}. </p>
*
* @see #clear()
*/
void cancel() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
target.removeCallback(this);
status = Status.CANCELLED;
if (loadStatus != null) {
loadStatus.cancel();
loadStatus = null;
}
}
起关键作用代码为
loadStatus.cancel();
public static class LoadStatus {
private final EngineJob<?> engineJob;
private final ResourceCallback cb;
LoadStatus(ResourceCallback cb, EngineJob<?> engineJob) {
this.cb = cb;
this.engineJob = engineJob;
}
public void cancel() {
engineJob.removeCallback(cb);
}
}
LoadStatus 实际上只是持有了ResourceCallback回调(该回调可获取资源加载成功或失败)和 EngineJob。 EngineJob 是负责加载资源,并在加载成功后回调回去,这里 SingleRequest 实现了回调,所以它便可得知资源加载完成并获取到。所以 cancel() 调用后,即使旧的加载请求完成也不会回调到 Tareget 上。
target.setRequest(request);
requestManager.track(target, request);
在该方法中,方法中,Target 持有了最新的 request , requestManager.track() 方法则触发了 request 的加载请求,实际是由内部 Engine 和 EngineJob 负责。当顺利加载成功后便回调到 Target 对象上,触发 target.onResourceReady(result, animation) 方法,图片便被正确显示出来了。
###########################################################
回到上面的流程,在into(view) 方法中,首先获取到了Request请求,然后开始执行Request。如果是复用的Request则直接执行begin(),否则执行track(target, request),但最终仍然会执行begin();
// ReqeustManager.java
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
// 与lifecycle绑定
targetTracker.track(target);
// 启动reqeust
requestTracker.runRequest(request);
}
// RequestTracker.java
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin(); // 立即开始加载
} else {
//防止从以前的请求中加载任何位图,释放该请求所拥有的任何资源,显示当前占位符(如果提供了该占位符),并将该请求标记为已取消。
// request.java( Interface )
request.clear();
pendingRequests.add(request); // 加入队列等待执行
}
}
Request类是interface类型,begin()是它的抽象方法,要想弄清楚begin()的具体实现,那就要先找到Request的实现类,SingleRequest ,我们直接去SingleReqeust类里面 看看begin方法如何实现的;
// SingleReqeust.java
public void begin() {
if (status == Status.COMPLETE) {
// 资源已下载,直接回调
// 执行动画
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
// 计算尺寸
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());
}
}
进入begin方法后首先判断如果资源已经过加载好了则直接回调onResourceReady显示图片并缓存,否则测量出图片尺寸后再开始加载图片(onSizeReady()中执行加载任务)并同时显示占位图: 接着再看onSizeReady()测量完图片尺寸后如何加载图片的:
// SingleRequest.java
@Override
public void onSizeReady(int width, int height) {
if (status != Status.WAITING_FOR_SIZE) {
return;
}
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);
}
可以看到真正的下载任务是在Engine类的load方法中实现的,其中也涉及到了图片缓存逻辑;
最终通过Handler机制,Glide从工作线程切换到主线程,并最终将Drawable对象显示到ImageView上; 具体再分析一下线程是如何切换的。
线程切换的过程
回到SingleRequest.onSizeReady()
# SingleRequest
@Override
public void onSizeReady(int width, int height) {
...
// 省略不相关代码
...
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);
}
#Engine
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb) {
Util.assertMainThread();
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
//focus1 更新相应属性创建缓存key--EngineKey
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//尝试从活跃的资源内存缓存中中获取
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;
}
//尝试从内存缓存中获取
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);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
//创建请求job
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
//创建解码job
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
//保存当前请求job
jobs.put(key, engineJob);
engineJob.addCallback(cb);
//开始请求
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
注意focus1处的代码
假设一个ImageView的宽高是300300,另一个ImageView的宽高是900900,则在这两个ImageView中加载同一张图片资源会缓存几次?
创建图片缓存Key和图片的model(图片链接Url)、图片资源的宽高都有关系,因此两个不同宽高的ImageView加载同一图片会缓存两次。
1.尝试从活跃的资源内存缓存中中获取资源,取到直接回调返回,没取到执行第二步 2.尝试从内存缓存中获取资源,取到直接回调返回,没取到执行第三步 3.创建请求engineJob 4.执行请求
#EngineJob
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
// focus1
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
DecodeJob实现了Runnable接口,这里将其添加到线程池中,接下来看下run方法 。
#DecodeJob
@Override
public void run() {
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
DataFetcher<?> localFetcher = currentFetcher;
try {
//判断是否已经被取消
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (Throwable t) {
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
} finally {
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
//根据当前流程步骤获取相应获取数据类(刚开始肯定为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);
}
}
# DecodeJob.getNextGenerator
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);
}
}
默认的AUTOMATIC方式是允许解码缓存的RESOURCE,所以在 getNextStage 会先返回Stage.RESOURCE_CACHE,然后在start中会返回diskCacheExecutor,然后开始执行DecodeJob,也就是说这里会获得一个ResourceCacheGenerator ,
#DecodeJob.runGenerators()
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();
}
}
在 runGenerators 中,会调用 startNext,目前currentGenerator是ResourceCacheGenerator, 那么就是调用它的startNext方法:
@Override
public boolean startNext() {
...
# 省略部分代码
...
// 这里会从registry中匹配相应的Modeloader来加载数据
loadData.fetcher.loadData(helper.getPriority(), this);
...
return started;
}
这里是loadData.fetcher是HttpUrlFetcher。
# HttpUrlFetcher.loadData()
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super InputStream> callback) {
// 省略部分代码
//连接网络获取图片流
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
//成功回调
callback.onDataReady(result);
}
请求成功之后回调了DataCallback方法。最终会回调到DecodeJob的onDataFetcherReady 方法,之后在进行解码操作: 解码成功之后,回调EngineJob中的onResourceReady方法:
# EngineJob
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
synchronized (this) {
this.resource = resource;
this.dataSource = dataSource;
}
notifyCallbacksOfResult();
}
在notifyCallbacksOfResult方法中:
# Engine.java
void notifyCallbacksOfResult() {
// 省略部分代码
engineJobListener.onEngineJobComplete(this, localKey, localResource);
for (final ResourceCallbackAndExecutor entry : copy) {
// focus
entry.executor.execute(new CallResourceReady(entry.cb));
}
decrementPendingCallbacks();
}
注意focus行的代码:
使用entry中的executor执行线程,而entry就是ResourceCallbackAndExecutor ,而它里面的executor正好是我们Executors.mainThreadExecutor() 。
很明显它是在这里切换到了主线程。
补充说明1:
首先回顾下主线程的创建,在RequestBuilder.java中的into方法中:
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
...
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
Executor.java
private static final Executor MAIN_THREAD_EXECUTOR =
new Executor() {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(@NonNull Runnable command) {
handler.post(command);
}
};
它最终会一层一层传递到EngineJob中。engineJob.addCallback(cb, callbackExecutor); 它将被实例化为一个ResourceCallbackAndExecutor对象并add到cbs集合中。
EngineJob.java
synchronized void addCallback(final ResourceCallback cb, Executor callbackExecutor) {
...
cbs.add(cb, callbackExecutor);
...
}
void add(ResourceCallback cb, Executor executor) {
callbacksAndExecutors.add(new ResourceCallbackAndExecutor(cb, executor));
}
补充说明2:
以上代码基于glide 4.11.0版本,可能代码有所不同,但是原理是一样。
参考: Android源码进阶之Glide加载流程和源码详解
|