Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。
从主流程分析
Glide最简单的使用:
Glide
.with(context)
.load("https://github.com/bumptech/glide/blob/master/static/glide_logo.png")
.into(iv)
Glide加载图片最简单的是三步:
-
Glide.with(context)
来获取Glide对象和RequestManager
对象并绑定Context
生命周期; -
RequestManager.load(url)
获取RequestBuilder
对象并绑定图片Url,此时还没有去加载Url地址; -
RequestBuilder.into(iv)
加载图片并且将获取到的图片显示到ImageView
中。
下面跟着三步一步一步来看下具体实现。
Glide.with(context)
com.bumptech.glide.Glide#with(Context)
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
return Glide.get(context).getRequestManagerRetriever();
}
// 获取Glide单例对象
public static Glide get(@NonNull Context context) {
if (glide == null) {
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
Glide.with()
一共有两大步:
-
getRetriever(context)
获取Glide
单例对象和RequestManagerRetriever
对象; -
get(context)
获取RequestManager
对象同时绑定当前Context
的生命周期。
Glide单例创建
Glide
对象的首次创建跟代码是从Glide.get(context)
->checkAndInitializeGlide()
->initializeGlide()
->GlideBuilder#build()
,最终通过建造者模式创建Glide
对象。
com.bumptech.glide.GlideBuilder#build
Glide build(@NonNull Context context) {
if (sourceExecutor == null) {
sourceExecutor = GlideExecutor.newSourceExecutor();
}
if (diskCacheExecutor == null) {
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
if (animationExecutor == null) {
animationExecutor = GlideExecutor.newAnimationExecutor();
}
if (memorySizeCalculator == null) {
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}
if (connectivityMonitorFactory == null) {
connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
}
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0) {
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
if (arrayPool == null) {
arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
}
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
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);
}
GlideExperiments experiments = glideExperimentsBuilder.build();
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory, experiments);
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptionsFactory,
defaultTransitionOptions,
defaultRequestListeners,
experiments);
}
创建Glide
对象的同时还创建其它很多的实例,包括缓存执行器SourceExecutor
和DiskCacheExecutor
,加载引擎Engine
,RequestManagerRetriever
等。
RequestManager创建
com.bumptech.glide.manager.RequestManagerRetriever#get(Context)
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)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper
// Only unwrap a ContextWrapper if the baseContext has a non-null application context.
// Context#createPackageContext may return a Context without an Application instance,
// in which case a ContextWrapper may be used to attach one.
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
这里做了很多Context
类型的区分,只要就是得到不同的生命周期类型:
- 在主线程并且不是
Application
,判断下是FragmentActivity
还是Activity
,都不是获取BaseContext
重新进来判断一遍; - 其余都作为
Application
来绑定生命周期。
我们选择FragmentActivity
分支来继续往下追:
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
frameWaiter.registerSelf(activity);
FragmentManager fm = activity.getSupportFragmentManager(); ①
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
@NonNull
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint); ②
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); ④
if (isParentVisible) {
requestManager.onStart();
}
current.setRequestManager(requestManager); ⑤
}
return requestManager;
}
- 第一步获取
Activity
对应的FragmentManager
; - 第二步根据
FragmentManager
获取对应Fragment
,如果没有创建一个新的SupportRequestManagerFragment
对象,并且放入到Map
中;如果已经存在,直接从Map
中获取; - 第三步,从
Fragment
中获取RequestManager
对象; - 第四步,如果没有获取到,就重新创建一个新的对象,第五步就是将新的
RequestManager
和Fragment
绑定。
这里的SupportRequestManagerFragment
其实就是一个空布局的Fragment
,主要作用是感知Activity
的生命周期。
RequestManager.load(url)
com.bumptech.glide.RequestManager#load(java.lang.String)
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
if (isAutoCloneEnabled()) {
return clone().loadGeneric(model);
}
this.model = model;
isModelSet = true;
return selfOrThrowIfLocked();
}
这个流程逻辑相对比较少的,主要就是创建了一个RequestBuilder
对象,并且它的泛型参数是Drawable
类型,因为我们分析的是加载Url到指定的ImageView
。
RequestBuilder.into(iv)
com.bumptech.glide.RequestBuilder#into(ImageView)
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
switch (view.getScaleType()) { ①
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
..... 省略其它缩放类型
}
}
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor()); ②
}
-
第一处查看
ImageView
是否设置了缩放类型,如果有添加类型至RequestOptions
中; -
进入
into()
方法中具体执行,这里传了四个参数: - 第一个
ImageView
目标,包含了资源类型就是Drawable.class
; - 第二个是请求监听
RequestListener
,包括了加载失败和资源准备完成两个回调,这里传的是空值; - 第三个是请求的选项
RequestOptions
; - 第四个是回调的线程池,这边最终回调到主线程。
- 第一个
into(target,reqeuestListener,options,callbackExecutor)
com.bumptech.glide.RequestBuilder#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()");
}
Request request = buildRequest(target, targetListener, options, callbackExecutor); ①
Request previous = target.getRequest(); ②
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { ③
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request); ④
return target;
}
-
第一步,构建一个
Request
对象,这个下面着重介绍下; -
第二步从
Target
对象里面获取已存在的请求; -
第三步判断是否可以复用已存在的请求:
- 第一个条件是
request
和previous
是否参数一致,请求类型一致; - 是否设置了跳过缓存并且
previous
已经完成。
- 第一个条件是
-
第四步如果不能复用,那么就使用构建的
Request
对象,最后调用RequestManager.track(target,request)
方法。
接着我们先暂停主流程,进入构建Request
对象的逻辑里面。
buildRequest(target,targetListener,opstions,callbackExecutor)
com.bumptech.glide.RequestBuilder#buildRequest
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
return buildRequestRecursive(
/*requestLock=*/ new Object(),
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
这里直接调用buildRequestRecursive()
方法。
com.bumptech.glide.RequestBuilder#buildRequestRecursive
private Request buildRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
// Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
ErrorRequestCoordinator errorRequestCoordinator = null;
if (errorBuilder != null) { ①
errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
Request mainRequest =
buildThumbnailRequestRecursive(
requestLock,
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor); ②
if (errorRequestCoordinator == null) { ③
return mainRequest;
}
int errorOverrideWidth = errorBuilder.getOverrideWidth();
int errorOverrideHeight = errorBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight) && !errorBuilder.isValidOverride()) {
errorOverrideWidth = requestOptions.getOverrideWidth();
errorOverrideHeight = requestOptions.getOverrideHeight();
}
Request errorRequest =
errorBuilder.buildRequestRecursive(
requestLock,
target,
targetListener,
errorRequestCoordinator,
errorBuilder.transitionOptions,
errorBuilder.getPriority(),
errorOverrideWidth,
errorOverrideHeight,
errorBuilder,
callbackExecutor);
errorRequestCoordinator.setRequests(mainRequest, errorRequest); ④
return errorRequestCoordinator;
}
- 第一步,判断
errorBuilder
是否为空,这个errorBuilder
是我们通过RequestBuilder.error()
设置的,如果不为空,将会生成一个协调器ErrorRequestCoordinator
用于协调下面mainRequest
和errorRequest
,现在我们默认未设置,只看主流程; - 第二步通过
buildThumbnailRequestRecursive()
生成mainRequest
; - 第三步如果
errorRequestCoordinator
为空直接返回mainRequest
; - 第四步如果
errorRequestCoordinator
不为空还将生成一个errorRequest
。
接着主流程我们看看mainRequest
是怎么生成的。
buildThumbnailRequestRecursive()
com.bumptech.glide.RequestBuilder#buildThumbnailRequestRecursive
private Request buildThumbnailRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
if (thumbnailBuilder != null) {
// Recursive case: contains a potentially recursive thumbnail request builder.
if (isThumbnailBuilt) {
throw new IllegalStateException(
"You cannot use a request as both the main request and a "
+ "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
}
TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
thumbnailBuilder.transitionOptions;
// Apply our transition by default to thumbnail requests but avoid overriding custom options
// that may have been applied on the thumbnail request explicitly.
if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
thumbTransitionOptions = transitionOptions;
}
Priority thumbPriority =
thumbnailBuilder.isPrioritySet()
? thumbnailBuilder.getPriority()
: getThumbnailPriority(priority);
int thumbOverrideWidth = thumbnailBuilder.getOverrideWidth();
int thumbOverrideHeight = thumbnailBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !thumbnailBuilder.isValidOverride()) {
thumbOverrideWidth = requestOptions.getOverrideWidth();
thumbOverrideHeight = requestOptions.getOverrideHeight();
}
ThumbnailRequestCoordinator coordinator =
new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
Request fullRequest =
obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
isThumbnailBuilt = true;
// Recursively generate thumbnail requests.
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(
requestLock,
target,
targetListener,
coordinator,
thumbTransitionOptions,
thumbPriority,
thumbOverrideWidth,
thumbOverrideHeight,
thumbnailBuilder,
callbackExecutor);
isThumbnailBuilt = false;
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
} else if (thumbSizeMultiplier != null) {
// Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
ThumbnailRequestCoordinator coordinator =
new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
Request fullRequest =
obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
BaseRequestOptions<?> thumbnailOptions =
requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);
Request thumbnailRequest =
obtainRequest(
requestLock,
target,
targetListener,
thumbnailOptions,
coordinator,
transitionOptions,
getThumbnailPriority(priority),
overrideWidth,
overrideHeight,
callbackExecutor);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
// Base case: no thumbnail.
return obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
}
}
这边我们先忽略缩略图的设置,直接看最后else
分支中,直接返回的是obtainRequest()
方法的返回值。
com.bumptech.glide.RequestBuilder#obtainRequest
private Request obtainRequest(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
return SingleRequest.obtain(
context,
glideContext,
requestLock,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
到这里停止,我们最终可以看到其实经过很多层最后得到的是SingleRequest
对象。接着我们需要跳回到into()
方法中的最后一行代码RequestManager.track(target,request)
,这里面的request
就是我们刚刚看到的SingleRequest
对象。
RequestManager.track(target,request)
com.bumptech.glide.RequestManager#track
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target); ①
requestTracker.runRequest(request); ②
}
com.bumptech.glide.manager.TargetTracker#track
private final Set<Target<?>> targets =
Collections.newSetFromMap(new WeakHashMap<Target<?>, Boolean>());
public void track(@NonNull Target<?> target) {
targets.add(target);
}
com.bumptech.glide.manager.RequestTracker#runRequest
private final Set<Request> requests =
Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
private final Set<Request> pendingRequests = new HashSet<>();
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
这个方法是加了synchronized
为了线程安全,一共作了两个操作:
- 第一步将
target
添加到TargetTracker.targets
集合中; - 第二步运行
SingleRequest
,首先将SingleRequest
添加到RequestTracker.requests
集合中,如果当前不是暂停状态,直接调用SingleRequest.begin()
方法,如果当前是暂停状态,那么就将SingleRequest
添加到待定的集合中pendingRequests
。
我们继续往下看,进入SingleRequest.begin()
方法。
SingleRequest.begin()
com.bumptech.glide.request.SingleRequest#begin
public void begin() {
synchronized (requestLock) {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) { ①
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
if (status == Status.RUNNING) { ②
throw new IllegalArgumentException("Cannot restart a running request");
}
if (status == Status.COMPLETE) { ③
onResourceReady(
resource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
return;
}
experimentalNotifyRequestStarted(model);
cookie = GlideTrace.beginSectionAsync(TAG);
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) { ④
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) { ⑤
target.onLoadStarted(getPlaceholderDrawable());
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
}
整个begin()
方法中,我么分为了5步来梳理:
- 第一步
model
也就是url
如果为空,直接返回,回调onLoadFailed()
; - 第二步判断当前状态如果是
RUNNING
状态,直接抛异常,一个Request
只能同时执行一次; - 第三步判断当前状态如果是
COMMPLETE
状态,那么可以直接返回resource
,onResourceReady()
后续会将获取到的Drawable
显示到指定的ImageView
中,这个后面会有解析; - 第四步判断宽高是否有效,如果有效直接进入
onSizeReady()
方法,开启加载模式,此时状态会进入RUNNING
状态; - 第五步如果当前状态为
RUNNING
或者WAITING_FOR_SIZE
状态,显示占位图。
SingleRequest.onSizeReady(width,height)
com.bumptech.glide.request.SingleRequest#onSizeReady
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
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); ②
}
}
- 第一步先将状态设置为
RUNNING
; - 启动
Engine
引擎去加载图片。
Engine.load()
com.bumptech.glide.load.engine.Engine#load
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,
Executor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options); ①
EngineResource<?> memoryResource;
synchronized (this) {
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime); ②
if (memoryResource == null) {
return waitForExistingOrStartNewJob(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
options,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache,
cb,
callbackExecutor,
key,
startTime); ③
}
}
// Avoid calling back while holding the engine lock, doing so makes it easier for callers to
// deadlock.
cb.onResourceReady(
memoryResource, DataSource.MEMORY_CACHE, false); ④
return null;
}
- 第一步生成
EngineKey
,用作后续写缓存或者读缓存使用; - 第二步去缓存中寻找,先从活动缓存ActivityResource,再去内存缓存中MemoryCache中;
- 第三步如果内存缓存中没有命中,那么开始新的任务
Engine.waitForExistingOrStartNewJob()
com.bumptech.glide.load.engine.Engine#waitForExistingOrStartNewJob
private <R> LoadStatus waitForExistingOrStartNewJob(...) {
// 从Jobs map中查找,已经存在就直接返回
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,
// 注意最后一次参数,传的是EngineJob,因为EngineJob实现了DecodeJob.Callback
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob); ③
// 存到Jobs map中
jobs.put(key, engineJob);
// 将EngineJob和callback,callbackExecutor绑定
// cb是回调资源是否加载完成,callbackExecutor是回调到主线程
engineJob.addCallback(cb, callbackExecutor);
// 调用EngineJob.start()其实就是调用线程池执行Runnable,而decodeJob就是实现了Runnable
engineJob.start(decodeJob); ④
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
- 第一步查找是否已经存在此
Job
,若已存在直接返回; - 第二步创建
EngineJob
对象,用于开启任务,回调资源加载成功和失败; - 第三步创建
DecodeJob
对象,用于加载资源,操作缓存等,并且此时DecodeJob
已经和EngineJob
以Callback
形式绑定在一起; - 第四步开始执行
DecodeJob
的run()
方法,EngineJob.start()
内部就是调用线程池的excute()
方法,传入的正是DecodeJob
,所以我们进入DecodeJob.run()
方法继续分析。
DecodeJob.run()
com.bumptech.glide.load.engine.DecodeJob#run
public void run() {
// This should be much more fine grained, but since Java's thread pool implementation silently
// swallows all otherwise fatal exceptions, this will at least make it obvious to developers
// that something is failing.
GlideTrace.beginSectionFormat("DecodeJob#run(reason=%s, model=%s)", runReason, model);
// 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(); ①
} catch (CallbackException e) {
throw e;
} finally {
if (localFetcher != null) {
// 回收资源,Http Stream、File Stream等
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
run()
方法内部直接进入runWrapped()
方法。
DecodeJob#runWrapped
com.bumptech.glide.load.engine.DecodeJob#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:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE
: getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
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:
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 enum RunReason {
/** 首次提交任务 */
INITIALIZE,
/** 尝试从磁盘缓存切到内存缓存 */
SWITCH_TO_SOURCE_SERVICE,
/**
* 解码原数据,也就是去加载资源
*/
DECODE_DATA,
}
先看下RunReason
这个枚举类,一共有三个状态:
-
INITIALIZE
:代表首次提交任务; -
SWITCH_TO_SOURCE_SERVICE
:磁盘缓存中有,切到内存缓存中; -
DECODE_DATA
:直接去加载资源(未命中缓存)。
然后我们再看runWrapped()
方法,runReason
变量在init()
方法中赋值为INITIALIZE
状态。这样我们先从第一个case
查看:默认缓存全开
- 首先通过
getNextStage(Stage.INITIALIZE)
获取下一个阶段,默认缓存全开,下一状态为Stage.RESOURCE_CACHE
; - 然后通过
getNextGenerator()
获取到下一个DataFetcherGenerator
,由于上面Stage
是RESOURCE_CACHE
,所以返回的是ResourceCacheGenerator
,这个Generator
就是从磁盘缓存中获取是否有经过编解码、转码之后的缓存; - 最后调用
runGenerators()
。
DecodeJob#runGenerators
com.bumptech.glide.load.engine.DecodeJob#runGenerators
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
// while循环,知道stage==SOURCE,才结束
while (!isCancelled
&& currentGenerator != null
&& !(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();
}
}
这里我们可以看到,进入while
循环,其中currentGenerator.startNext()
是获取ResourceCacheGenerator
是否已存在缓存,如果存在那么就直接返回了,不存在继续往下走,直到stage=Stage.Source
,然后调用reschedule()
方法。
DecodeJob#reschedule
com.bumptech.glide.load.engine.DecodeJob#reschedule
public void reschedule() {
// 首先将runReason置为SWITCH_TO_SOURCE_SERVICE
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
// 然后调用callback.reschedule(this)
callback.reschedule(this);
}
- 第一步改变
runReason
值,置为SWITCH_TO_SOURCE_SERVICE
; - 第二步调用
callback.reschedule()
方法,前面创建DecodeJob
对象的时候提过,这里的callback
就是EngineJob
对象,所以我们又得回到EngineJob.reschedule()
方法。
EngineJob#reschedule
com.bumptech.glide.load.engine.EngineJob#reschedule
public void reschedule(DecodeJob<?> job) {
// Even if the job is cancelled here, it still needs to be scheduled so that it can clean itself
// up.
getActiveSourceExecutor().execute(job);
}
这里拿到sourceExecutor
的线程池,再去执行DecodeJob.run()
方法...有点头晕
但是几个状态我们需要知道,对于DecodeJob
,它的runReason
已经是SWITCH_TO_SOURCE_SERVICE
并且stage
是SOURCE
了。
到这之后又会回到DecodeJob.run()
方法,然后去DataSourceGenerator
去查找是否有源文件缓存,如果有直接返回,没有就去SourceGenerator
去加载资源。
总结加载流程:
- 先从
ResourceCacheGenerator
中去寻找是否有经过转换、解码之后的磁盘文件缓存,这个缓存要比源文件缓存小; - 再从
DataSourceGenerator
中寻找源文件磁盘缓存,这个是加载的源文件直接写入缓存; - 如果都没命中,那么就去
Http
请求资源,资源请求回来之后先写入磁盘缓存,再返回到Target
。
最后我们看下资源拿到之后是如何回调到Target
,当资源得到之后,会调用onResourceReady()
回调方法,此方法的回调链为:SingleRequest#onResourceReady
->ImageViewTarget#onResourceReady
->mageViewTarget#setResourceInternal
->DrawableImageViewTarget#setResource
com.bumptech.glide.request.target.DrawableImageViewTarget#setResource
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
最终在DrawableImageViewTarget
中降Resource
设置给ImageView
。
为了大家更便捷的对这源码分析,我将方法引用都放在代码块的最上方,大家可以参考。
Glide源码很多不容易一时间啃完,大家可以多读读多看看,了解下每个对象的工作内容,然后再去反复理解,加载逻辑中涉及到缓存的查找已经资源的加载,理清楚之后就会觉得豁然开朗,加油~
网友评论