一般情况下,我们用Glide加载图片如下:
Glide.with(this).load(url).into(imageView);
接下来基于Glide4.9.0源码分析图片加载主线流程。
with是Glide提供的有一组静态方法,它有好几个重载方法,如下所示:
public class Glide{
...
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getContext()).get(fragment);
}
@Deprecated
@NonNull
public static RequestManager with(@NonNull android.app.Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
@NonNull
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
}
可以看到,with方法的重载种类非常多,可以传入Context,FragmentActivity,Activity,Fragment,View等类型。每一个with方法都非常类似,都是先调用一个getRetriever方法然后调用一个get方法。
getRetriever方法返回一个RequestManagerRetriever的类型,如下所示:
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// Context could be null for other reasons (ie the user passes in null), but in practice it will
// only occur due to errors with the Fragment lifecycle.
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();
}
接下来我们看下RequestManagerRetriever 的get方法
public class RequestManagerRetriever implements Handler.Callback{
...
@NonNull
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;
}
@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
// 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);
}
@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));
}
}
@NonNull
public RequestManager get(@NonNull Fragment fragment) {
Preconditions.checkNotNull(
fragment.getContext(),
"You cannot start a load on a fragment before it is attached or after it is destroyed");
if (Util.isOnBackgroundThread()) {
return get(fragment.getContext().getApplicationContext());
} else {
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet(fragment.getContext(), fm, fragment, fragment.isVisible());
}
}
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull View view) {
if (Util.isOnBackgroundThread()) {
return get(view.getContext().getApplicationContext());
}
Preconditions.checkNotNull(view);
Preconditions.checkNotNull(
view.getContext(), "Unable to obtain a request manager for a view without a Context");
Activity activity = findActivity(view.getContext());
// The view might be somewhere else, like a service.
if (activity == null) {
return get(view.getContext().getApplicationContext());
}
// Support Fragments.
// Although the user might have non-support Fragments attached to FragmentActivity, searching
// for non-support Fragments is so expensive pre O and that should be rare enough that we
// prefer to just fall back to the Activity directly.
if (activity instanceof FragmentActivity) {
Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
return fragment != null ? get(fragment) : get(activity);
}
// Standard Fragments.
android.app.Fragment fragment = findFragment(view, activity);
if (fragment == null) {
return get(activity);
}
return get(fragment);
}
...
@SuppressWarnings("deprecation")
@Deprecated
@NonNull
RequestManagerFragment getRequestManagerFragment(Activity activity) {
return getRequestManagerFragment(
activity.getFragmentManager(), /*parentHint=*/ null, isActivityVisible(activity));
}
@SuppressWarnings("deprecation")
@NonNull
private RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
@SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"})
@Deprecated
@NonNull
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;
}
@NonNull
SupportRequestManagerFragment getSupportRequestManagerFragment(
Context context, FragmentManager fragmentManager) {
return getSupportRequestManagerFragment(
fragmentManager, /*parentHint=*/ null, isActivityVisible(context));
}
private static boolean isActivityVisible(Context context) {
// This is a poor heuristic, but it's about all we have. We'd rather err on the side of visible
// and start requests than on the side of invisible and ignore valid requests.
Activity activity = findActivity(context);
return activity == null || !activity.isFinishing();
}
@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;
}
@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;
}
}
上述代码看上去逻辑有点复杂,梳理下可以发现,RequestManagerRetriever类中的get方法大致分为两种情况,即传入Application类型的参数和非Application类型的参数。
对于传入Application类型的参数,如果在Glide.with()方法中传入的是一个Application对象,会调用getApplicationManager方法来获取一个RequestManager对象,此时,Glide加载的生命周期和Application的生命周期是同步的,Application的生命周期就是应用程序的生命周期,所以如果应用程序关闭的话,Glide的加载也会同时终止。另外,如果是在非主线程中使用的Glide,不管传入的是Fragment还是Activity,都会被强制当成Application来处理。
对于传入非Application类型的情况。不管你Glide.with方法中传入的是Fragment还是Activity,都会向当前的Activity中加入一个隐藏的Fragment,并返回一个RequestManager对象,这个RequestManager对象中保存有隐藏Fragment的生命周期,这样如果加载图片的Activity被销毁了,隐藏Fragmeng可以监听到,这样Glide就可以捕获这个事件从而停止加载图片。
总的来说,with方法根据传入的参数来确定加载图片的生命周期,并且最终都会得到一个RequestManager的对象。
RequestManager的load方法也有很多重载方法,如下所示:
public class RequestManager implements LifecycleListener, ModelTypes>{
...
@NonNull
@CheckResult
public RequestBuilder asBitmap() {
return as(Bitmap.class).apply(DECODE_TYPE_BITMAP);
}
@NonNull
@CheckResult
public RequestBuilder asGif() {
return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
}
@NonNull
@CheckResult
public RequestBuilder asDrawable() {
return as(Drawable.class);
}
@NonNull
@CheckResult
public RequestBuilder as(
@NonNull Class resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
@NonNull
@CheckResult
@Override
public RequestBuilder load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
@NonNull
@CheckResult
@Override
public RequestBuilder load(@Nullable Drawable drawable) {
return asDrawable().load(drawable);
}
@NonNull
@CheckResult
@Override
public RequestBuilder load(@Nullable String string) {
return asDrawable().load(string);
}
@NonNull
@CheckResult
@Override
public RequestBuilder load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
@NonNull
@CheckResult
@Override
public RequestBuilder load(@Nullable File file) {
return asDrawable().load(file);
}
@SuppressWarnings("deprecation")
@NonNull
@CheckResult
@Override
public RequestBuilder load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return asDrawable().load(resourceId);
}
@SuppressWarnings("deprecation")
@CheckResult
@Override
@Deprecated
public RequestBuilder load(@Nullable URL url) {
return asDrawable().load(url);
}
@NonNull
@CheckResult
@Override
public RequestBuilder load(@Nullable byte[] model) {
return asDrawable().load(model);
}
@NonNull
@CheckResult
@Override
public RequestBuilder load(@Nullable Object model) {
return asDrawable().load(model);
}
...
}
从上面代码中可以看到,load方法中会先调用一个as函数,像asBitmap,asGif或者asDrawable,as系列函数会返回一个RequestBuilder的泛型对象,然后调用该对象的load函数。
RequestBuilder的load函数如下所示:
@NonNull
@CheckResult
@SuppressWarnings("unchecked")
@Override
public RequestBuilder load(@Nullable Object model) {
return loadGeneric(model);
}
@NonNull
private RequestBuilder loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
另外可以看到RequestBuilder继承了BaseRequestOptions,而BaseRequestOptions中封装了我们日常常用一些方法,比如error,placeholder,override,skipMemoryCache,diskCacheStrategy等等方法,这里由于只分析Glide加载图主线流程,就不会这个方法进行深入分析了。
load方法返回RequestBuilder对象之后,接下来我们分析into方法。
into方法是整个Glide加载图片过程中最复杂的一部分。
into方法代码如下:
@NonNull
public ViewTarget 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());
}
最后一行会调用glideContext.buildImageViewTarget(view, transcodeClass)来构建一个target对象,这个target对象是用来显示图片用的,我们来看下:
@NonNull
public ViewTarget buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
这里会调用ImageViewTargetFactory的buildTarget()方法,代码如下:
public class ImageViewTargetFactory {
@NonNull
@SuppressWarnings("unchecked")
public ViewTarget buildTarget(
@NonNull ImageView view, @NonNull Class clazz) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (ViewTarget) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
}
在buildTarget()方法中会根据传入的class参数来构建不同的Target对象,那这个class参数从哪里来呢,追溯可知,这个在前面load的时候由调用asBitmap(),asDrawable()等方法,默认情况下是asDrawable,里面的as方法传入的是Drawable.class,如果加载图片时加上了asBitmap,那么里面会调用as方法并传入Bitmap.class,而这个就是最终传递到buildTarget()方法的class参数。所以,如果你在使用Glide加载图片的时候调用了asBitmap()方法,那么这里就会构建出BitmapImageViewTarget对象,否则的话构建的都是DrawableImageViewTarget对象。
这里我们分析一般情况,也就是说buildImageViewTarget会创建一个DrawableImageViewTarget对象。接着我们继续进入上面into方法最后一行分析:
private > Y into(
@NonNull Y target,
@Nullable RequestListener targetListener,
BaseRequestOptions> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request 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;
}
这里会通过buildRequest方法创建一个request的对象。如果这个target上之前已经创建过一个request对象previous并且和新创建的request相等,就调用previous的begin方法,否则调用requestManager.clear(target),并设置target的request为新创建的request,然后调用requestManager.track(target, request)方法,我们看看这个track方法。
synchronized void track(@NonNull Target> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
这里继续调用了 requestTracker.runRequest(request);
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是一个接口,那么这个Request接口的具体实现在哪里呢,我们回到上面的buildRequest()方法就可以知道。
private Request buildRequest(
Target target,
@Nullable RequestListener targetListener,
BaseRequestOptions> requestOptions,
Executor callbackExecutor) {
return buildRequestRecursive(
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
private Request buildRequestRecursive(
Target target,
@Nullable RequestListener 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;
}
buildRequest()方法会调用buildRequestRecursive()方法,buildThumbnailRequestRecursive方法中又会调用buildThumbnailRequestRecursive()方法,接下来我们看看buildThumbnailRequestRecursive()方法。
private Request buildThumbnailRequestRecursive(
Target target,
RequestListener 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);
}
}
private Request obtainRequest(
Target target,
RequestListener 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);
}
buildThumbnailRequestRecursive()方法中大部分代码在处理缩略图,只看主要流程的话,这里会调用最后else里面的obtainRequest()方法,在obtainRequest()方法中会继续调用SingleRequest.obtain()来获取Request,我们继续看。
public final class SingleRequest
implements Request, SizeReadyCallback, ResourceCallback, FactoryPools.Poolable {
...
public static SingleRequest obtain(
Context context,
GlideContext glideContext,
Object model,
Class transcodeClass,
BaseRequestOptions> requestOptions,
int overrideWidth,
int overrideHeight,
Priority priority,
Target target,
RequestListener targetListener,
@Nullable List> requestListeners,
RequestCoordinator requestCoordinator,
Engine engine,
TransitionFactory super R> animationFactory,
Executor callbackExecutor) {
@SuppressWarnings("unchecked")
SingleRequest request = (SingleRequest) 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()方法中会创建一个SingleRequest对象,所以前面调用Request的begin方法就是这里SingleRequest的begin()方法,我们继续看。
@Override
public synchronized void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
// Only log at more verbose log levels if the user has set a fallback drawable, because
// fallback Drawables indicate the user expects null models occasionally.
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
// If we're restarted after we're complete (usually via something like a notifyDataSetChanged
// that starts an identical request into the same Target or View), we can simply use the
// resource and size we retrieved the last time around and skip obtaining a new size, starting a
// new load etc. This does mean that users who want to restart a load because they expect that
// the view size has changed will need to explicitly clear the View or Target before starting
// the new load.
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
// Restarts for requests that are neither complete nor running can be treated as new requests
// and can run again from the beginning.
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方法分两种情况,一种是使用了override() API为图片指定了一个固定的宽高,一种是没有指定。如果指定了的话,就会调用onSizeReady()方法,如果没有指定的话,会调用target.getSize(this),这里的this是SizeReadyCallback,target.getSize()方法的内部会根据ImageView的layout_width和layout_height的值做一系列的计算,来算出图片应该的宽高,计算完之后回调SizeReadyCallback的onSizeReady()方法,所以,最终都会调用onSizeReady()方法,我们继续分析onSizeReady()方法。
@Override
public synchronized void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
if (IS_VERBOSE_LOGGABLE) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
if (IS_VERBOSE_LOGGABLE) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadStatus =
engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this,
callbackExecutor);
// This is a hack that's only useful for testing right now where loads complete synchronously
// even though under any executor running on any thread but the main thread, the load would
// have completed asynchronously.
if (status != Status.RUNNING) {
loadStatus = null;
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
可以看到onSizeReady()方法中最终回到用engine.load()方法,并传入一些列的参数,由于篇幅原因,下一篇Glide加载图片源码分析(二)将继续讲解Glide图片加载流程。