Android 进阶学习(十二) Glide源码学习(一) 图片
Glide 作为Google 出品的图片加载库,在开发的过程中对我们的帮助是非常大的,网上也有很多关于他的文章,说他怎么怎么好,但是他就是再好我们如果不知道他的原理也肯定是记不住的,而且关于图片的操作在面试过程中是必然要问到的,如果你只是知道怎么用的话肯定是不能打动面试官的,如果你能从源码方面说一下,肯定会让对方眼前一亮的,废话不多说,我们由简入繁的开始分析一下一张图片在Glide都经历了什么,
想要弄清楚整个图片的加载过程,如果上来就看源码的话大家肯定会非常懵,还是需要先弄清楚每个类在Glide中扮演的角色,这样便于大家的理解,即使部分代码不懂,但是知道了他是干什么也能猜测一个大概,同时也方便我们在分析过程中查看
Glide 中重要的角色
1.Glide
Glide作为图片加载的入口, 当中保存着非常重要的数据,在整个请求中非常重要,创建方式: DCL 单例
2.RequestManagerRetriever
RequestManagerRetriever 作为RequestManager 管理者,调度着当前请求应该分配给哪个RequestManager,创建方式:new 伴随着Glide同时创建
3.RequestManager
RequestManager 作为请求的承载者,中控器, 在当中扮演着非常重要的角色, 创建方式: new 不同的是并不是每次请求都创建,而是在同一个activity中只创建一个,部分情况可能将这个请求分配给ApplicationContext,
4.Request
这个一看就知道是请求, 重要的请求类 SingleRequest ThumbnailRequestCoordinator (包含2个请求,判断也非常简单,后面我们会单独做分析)
创建方式 : 缓存池 ,防止大量创建对象浪费时间,频繁销毁对象导致内存抖动,同样的方式 Handler.obtainMessage 也是如此
5.RequestBuilder
用来构建请求时的参数,通常会继承开发者在全局的配置,如果有改动会替换响应的改动.创建方式:new 无特殊方式,但是需要注意的是RequestBuilder的创建开始的方法是 as(classType.class) ,即使是Glide.with(context).load(resId),看似我们是调用的load 的方法创建了这个RequestBuilder,实际操作还是调用的as 方法
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return asDrawable().load(resourceId);
}
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
6.Target
Target 是作为回调参与进来的,他不仅仅参与下载后作为最后资源出口,还会参与下载过程中获取图片的载体的宽高等等,
7.Engine
Engine 的做用是发起请求,实际的请求过程就是在他的内部实现的,创建方式:new 伴随着Glide 创建的
至此整个加载过程中涉及到的角色我们就分析完了,下面我们进入正题,开始分析一下最简单的请求
Glide.with(context).load(resId).into(imageView);
Glide.with(context)
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
先是getRetriever ,通过getRetriever 来获取RequestManager
Glide.getRetriever(@Nullable Context context)
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
Preconditions.checkNotNull(
context,
"You cannot start a load on a not yet attached View or a Fragment where getActivity() "
+ "returns null (which usually occurs when getActivity() is called before the Fragment "
+ "is attached or after the Fragment is destroyed).");
return Glide.get(context).getRequestManagerRetriever();
}
显示check一下context ,然后通过Glide 获取RequestManagerRetriever
Glide.get(@NonNull Context context)
private static volatile Glide glide;
@NonNull
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) {
// In the thread running initGlide(), one or more classes may call Glide.get(context).
// Without this check, those calls could trigger infinite recursion.
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) {
initializeGlide(context, new GlideBuilder());
}
GlideBuilder.build(Context context)
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor(),
isActiveResourceRetentionAllowed);
}
if (defaultRequestListeners == null) {
defaultRequestListeners = Collections.emptyList();
} else {
defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
}
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
这里的GlideBuilder 初始化了非常多的配置信息,这里我贴了两个比较重要的Engine 和RequestManagerRetriever ,可以看到这些都是伴随着Glide 同时初始化的,也就是整个工程就只有一个,
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
现在再看上面的方法大家应该已经知道了getRetriever()方法的大概,如果是第一次调用的话会使用DCL单利模式创建 Glide ,伴随着Glide 的创建同时会初始化一些配置信息比如 : RequestManagerRetriever Engine 等
RequestManagerRetriever.get(context)
@NonNull
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) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
可以看到如果不是在主线程就使用ApplicationManage,这里我看一下FragmentActivity的分支,他的处理方法比较特殊,具体怎么特殊我们进去看一下,
RequestManagerRetriever.get(@NonNull FragmentActivity activity)
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
这里没啥东西,继续往里面走supportFragmentGet
@NonNull
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
在这里看到了创建RequestManager 的方法,同时把自己创建的Fragemnt的 Lifecycle传递给了 RequestManager , 供RequestManager 来监听宿主Activity的状态,来停止请求,这里我们粘贴一些方法
RequestManager(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,
ConnectivityMonitorFactory factory,
Context context) {
this.glide = glide;
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.context = context;
connectivityMonitor =
factory.build(
context.getApplicationContext(),
new RequestManagerConnectivityListener(requestTracker));
// If we're the application level request manager, we may be created on a background thread.
// In that case we cannot risk synchronously pausing or resuming requests, so we hack around the
// issue by delaying adding ourselves as a lifecycle listener by posting to the main thread.
// This should be entirely safe.
if (Util.isOnBackgroundThread()) {
mainHandler.post(addSelfToLifecycle);
} else {
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
.....
}
lifecycle.addListener(this); 方法将自身作为参数,就可以监听到状态了,
我们看看RequestManager在生命周期方法中他都干了什么
@Override
public synchronized void onStart() {
resumeRequests();
targetTracker.onStart();
}
/**
* Lifecycle callback that unregisters for connectivity events (if the
* android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads.
*/
@Override
public synchronized void onStop() {
pauseRequests();
targetTracker.onStop();
}
/**
* Lifecycle callback that cancels all in progress requests and clears and recycles resources for
* all completed requests.
*/
@Override
public synchronized void onDestroy() {
targetTracker.onDestroy();
for (Target<?> target : targetTracker.getAll()) {
clear(target);
}
targetTracker.clear();
requestTracker.clearRequests();
lifecycle.removeListener(this);
lifecycle.removeListener(connectivityMonitor);
mainHandler.removeCallbacks(addSelfToLifecycle);
glide.unregisterRequestManager(this);
}
在onDestroy 中回收信息,onStart 开始请求,onStop 暂停请求,看到这里我就知道了Glide 是如何与生命周期作为绑定的,
看到这里我们发现他将RequestManager 放到了SupportRequestManagerFragment 里面,过去看了一下SupportRequestManagerFragment ,他就是一个普通的Fragment,没什么特别的,我们继续看看他是如何得到这个Fragment的,继续看getSupportRequestManagerFragment
@NonNull
private SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingSupportRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
看到这里我们恍然大悟,他在FragmentActivity中绑定了一个Fragment,通过这个Fragment来共享改Activity 的RequestManager ,同时可以感知这个Activity 的 声明周期,
看到了这里已经将Glide.with(context) 看完了,继续看load(String url)
RequestManager.load(@Nullable String string)
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
可以看到即使我们调用RequestManager.load()方法,他最终还是调用了as 方法来new RequestBuilder,设置其他参数这里就不分析了,继续看RequestBuilder.into(@NonNull ImageView view)
RequestBuilder.into(@NonNull ImageView view)
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// Clone in this method so that if we use this RequestBuilder to load into a View and then
// into a different target, we don't retain the transformation applied based on the previous
// View's scale type.
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
这里针对ScanType 做了一些配置参数,但是我们使用的是最简单的方法,所以这些参数都没有,直接看下面的into 方法,
可以看到into方法的第一个参数是通过glideContext ,view ,transcodeClass就是我们使用 load 的时候所调用的as 方法中Drawable,
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
这里调用了ImageViewTargetFactory 的 buildTarget方法,没有什么特别的,
ImageViewTargetFactory.buildTarget(@NonNull ImageView view,@NonNull Class<Z> clazz)
public class ImageViewTargetFactory {
@NonNull
@SuppressWarnings("unchecked")
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
@NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
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)");
}
}
}
可以看到如果是Drawable的话返回的就是DrawableImageViewTarget ,回去继续看into 方法
RequestBuilder <Y extends Target<TranscodeType>> Y into( @NonNull Y target,@Nullable RequestListener<TranscodeType> targetListener,BaseRequestOptions<?> options, Executor callbackExecutor)
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)) {
request.recycle();
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
previous.begin();
}
return target;
}
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
看到这里我们终于将请求时候的参数都已经创建完毕了,已经开始创建Request 了,这里看到他首先判断了 isModelSet 这个变量,isModelSet这个变量就是在调用load 方法的时候设置true 的,所以看他抛出异常的文言,在into 方法之前必须先调用load 方法,接下来构建了一个Request
RequestBuilder buildRequest
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
return buildRequestRecursive(
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
这里获取了RequestBuilder 的OverrideWidth和OverrideHeight,但是我们没有设置,这里应该是默认值,''
RequestBuilder 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) {
// Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
ErrorRequestCoordinator errorRequestCoordinator = null;
if (errorBuilder != null) {
errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
Request mainRequest =
buildThumbnailRequestRecursive(
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(
target,
targetListener,
errorRequestCoordinator,
errorBuilder.transitionOptions,
errorBuilder.getPriority(),
errorOverrideWidth,
errorOverrideHeight,
errorBuilder,
callbackExecutor);
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
这里我们没有设置erroe的信息, 所以返回的是buildThumbnailRequestRecursive
RequestBuilder 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) {
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(parentCoordinator);
Request fullRequest =
obtainRequest(
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
isThumbnailBuilt = true;
// Recursively generate thumbnail requests.
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(
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(parentCoordinator);
Request fullRequest =
obtainRequest(
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
BaseRequestOptions<?> thumbnailOptions =
requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);
Request thumbnailRequest =
obtainRequest(
target,
targetListener,
thumbnailOptions,
coordinator,
transitionOptions,
getThumbnailPriority(priority),
overrideWidth,
overrideHeight,
callbackExecutor);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
// Base case: no thumbnail.
return obtainRequest(
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
}
}
这里没有设置缩略图信息,所以调用的是obtainRequest
RequestBuilder 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) {
return SingleRequest.obtain(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
}
没有逻辑,继续向下看
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) {
request = new SingleRequest<>();
}
request.init(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
engine,
animationFactory,
callbackExecutor);
return request;
}
看到了obtain 这个方法有没有想起来Handler.obtainMessage 的方法,没错,他们的逻辑都是一样的,使用了一个常量池来保存信息,这样可以节省创建对象的时间,和频繁销毁对象造成的内存抖动
这里我们看到如果没有设置缩略图信息和error 信息的时候都是创建SingleRequest 实例,我们回头继续看我们没看完的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)) {
request.recycle();
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
previous.begin();
}
return target;
}
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
这里他将target 和request 绑定了,所以才有target.getRequest(); 和 target.setRequest(request); 这两个方法,既然将他们绑定再来看 target.getRequest();,就知道他是什么意思,也就是获取之前绑定的请求,如果前后两个请求相同,则放弃新创建的请求,直接返回原来已有的请求,继续看看是如何将target 和 request 绑定的
ViewTarget.setRequest(@Nullable Request request)
@Override
public void setRequest(@Nullable Request request) {
setTag(request);
}
private void setTag(@Nullable Object tag) {
if (tagId == null) {
isTagUsedAtLeastOnce = true;
view.setTag(tag);
} else {
view.setTag(tagId, tag);
}
}
这个绑定就是将这个request 设置为view的tag,
接下来就应该是请求了requestManager.track(target, request); 就是将这个target 放入已请求的队列里面,同时开始请求
RequestManager track(@NonNull Target<?> target, @NonNull Request request)
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
RequestManager runRequest
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);
}
}
看到了根据一个标识位来判断是否开启请求,这个请求就是根据生命周期判断的,上面我们已经分析过了,这里的调用了request.begin() 方法,我们在上面中创建Request是SingleRequest,去看他的begin方法
SingleRequest begin
public synchronized void begin() {
this.assertNotCallingCallbacks();
this.stateVerifier.throwIfRecycled();
this.startTime = LogTime.getLogTime();
if (this.model == null) {
if (Util.isValidDimensions(this.overrideWidth, this.overrideHeight)) {
this.width = this.overrideWidth;
this.height = this.overrideHeight;
}
int logLevel = this.getFallbackDrawable() == null ? 5 : 3;
this.onLoadFailed(new GlideException("Received null model"), logLevel);
} else if (this.status == SingleRequest.Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
} else if (this.status == SingleRequest.Status.COMPLETE) {
this.onResourceReady(this.resource, DataSource.MEMORY_CACHE);
} else {
this.status = SingleRequest.Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(this.overrideWidth, this.overrideHeight)) {
this.onSizeReady(this.overrideWidth, this.overrideHeight);
} else {
this.target.getSize(this);
}
if ((this.status == SingleRequest.Status.RUNNING || this.status == SingleRequest.Status.WAITING_FOR_SIZE) && this.canNotifyStatusChanged()) {
this.target.onLoadStarted(this.getPlaceholderDrawable());
}
if (IS_VERBOSE_LOGGABLE) {
this.logV("finished run method in " + LogTime.getElapsedMillis(this.startTime));
}
}
}
这里还是判断了一些状态,如果状态是正确的,就会根据我们是否设置了overrideWidth与overrideHeight 来判断走哪一个方法,如果我们设置了,那就是我们已经知道了需要加载的图片大小,如果不知道,就需要调用target 去计算宽高,
ViewTarget.getSize
void getSize(@NonNull SizeReadyCallback cb) {
int currentWidth = getTargetWidth();
int currentHeight = getTargetHeight();
if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
cb.onSizeReady(currentWidth, currentHeight);
return;
}
// We want to notify callbacks in the order they were added and we only expect one or two
// callbacks to be added a time, so a List is a reasonable choice.
if (!cbs.contains(cb)) {
cbs.add(cb);
}
if (layoutListener == null) {
ViewTreeObserver observer = view.getViewTreeObserver();
layoutListener = new SizeDeterminerLayoutListener(this);
observer.addOnPreDrawListener(layoutListener);
}
}
这里需要等待ViewTree 的回调,在成功后会回调request 的onSizeReady 方法将计算后的宽高传入,
SingleRequest onSizeReady
public synchronized void onSizeReady(int width, int height) {
this.stateVerifier.throwIfRecycled();
if (IS_VERBOSE_LOGGABLE) {
this.logV("Got onSizeReady in " + LogTime.getElapsedMillis(this.startTime));
}
if (this.status == SingleRequest.Status.WAITING_FOR_SIZE) {
this.status = SingleRequest.Status.RUNNING;
float sizeMultiplier = this.requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
if (IS_VERBOSE_LOGGABLE) {
this.logV("finished setup for calling load in " + LogTime.getElapsedMillis(this.startTime));
}
this.loadStatus = this.engine.load(this.glideContext, this.model, this.requestOptions.getSignature(), this.width, this.height, this.requestOptions.getResourceClass(), this.transcodeClass, this.priority, this.requestOptions.getDiskCacheStrategy(), this.requestOptions.getTransformations(), this.requestOptions.isTransformationRequired(), this.requestOptions.isScaleOnlyOrNoTransform(), this.requestOptions.getOptions(), this.requestOptions.isMemoryCacheable(), this.requestOptions.getUseUnlimitedSourceGeneratorsPool(), this.requestOptions.getUseAnimationPool(), this.requestOptions.getOnlyRetrieveFromCache(), this, this.callbackExecutor);
if (this.status != SingleRequest.Status.RUNNING) {
this.loadStatus = null;
}
if (IS_VERBOSE_LOGGABLE) {
this.logV("finished onSizeReady in " + LogTime.getElapsedMillis(this.startTime));
}
}
}
看到这里整个加载的过程我们就已经分析完毕了,整个过程还是非常复杂的,但是只要足够耐心还是能看懂的,