Glide.with(this) // 返回RequestManager对象
.load(imageUrl) // 返回Y extends Target对象,设置model属性
.into(imageView); // 最复杂
也可以有其它操作:
// 设置加载尺寸
Glide.with(this).load(imageUrl).override(800, 800).into(imageView);
// 设置加载中以及加载失败图片(api里面对placeholder()、error()函数中有多态实现)
Glide.with(this).load(imageUrl)
.placeholder(R.mipmap.ic_launcher).error(R.mipmap.ic_launcher).into(imageView);
// 设置加载动画
Glide.with(this).load(imageUrl).animate(R.anim.item_alpha_in).into(imageView);
// 设置要加载的内容,如图文混排
Glide.with(this).load(imageUrl).centerCrop().into(new SimpleTarget() {
@Override
public void onResourceReady(GlideDrawable resource, GlideAnimation glideAnimation) {
imageView.setImageDrawable(resource);
}
});
这里会根据Glide加载的with、load、into 三个步骤的源码进行分析了解。
一、withGlide中的with是一组静态方法,有以下几个重载,可以传入Activity、Fragment或者是Context。每个with()方法重载的代码,都是先调用RequestManagerRetriever的静态get()方法得到一个RequestManagerRetriever对象(这个静态get()方法就是一个单例实现)然后再调用RequestManagerRetriever的实例get()方法,去获取RequestManager对象。
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
public static RequestManager with(Activity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
public static RequestManager with(FragmentActivity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static RequestManager with(android.app.Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
public static RequestManager with(Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
get的相关代码就不贴了,关于传参的部分可以分为两类:传入Application类型的参数 和 传入非Application类型的参数。
case1(最简单):如果在Glide.with()方法中传入的是一个Application对象,或在子线程调用,那么这里就会调用getApplicationManager(context)方法来获取一个RequestManager对象。此时Glide的生命周期和Application对象的生命周期同步。应用程序一旦关闭,Glide的加载也就戛然而止了。
case2:如果传入的是Activity、FragmentActivity、Fragment等,最终都会向当前的Activity当中添加一个隐藏的Fragment(即fragmentGet、supportFragmentGet方法,分别对应的app包和v4包下的两种Fragment)。之所以要添加一个隐藏的Fragment,其实和生命周期也有关系。因为Glide不知道Activity的生命周期,Glide将自己和这个隐藏的Fragment绑在一起,而Fragment的生命周期和Activity是同步的。所以一旦Activity被销毁了,Glide也就可以及时的停止加载了。
总结来看,就是为了得到一个RequestManager对象,然后Glide会根据我们传入with()方法的参数来确定图片加载的生命周期。
二、loadwith方法返回的是一个RequestManager对象,紧接着就调用load方法。可以得知,load方法是属于RequestManager的。
@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(@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方法有包含Bitmap 、Drawable、String 、Uri、File等多种类型的重载,最后都是调用 asDrawable() 的load,并将 load()方法中的参数以model传递。看一下asDrawable() 方法:
// RequestManager类
@NonNull
@CheckResult
public RequestBuilder asDrawable() {
return as(Drawable.class);
}
@NonNull
@CheckResult
public RequestBuilder as(
@NonNull Class resourceClass) {
return new RequestBuilder(glide, this, resourceClass, context);
}
asDrawable()方法最终会return一个new出来的RequestBuilder对象,换句话说,调用的load方法属于RequestBuilder类:
// RequestBuilder类
@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;
}
闹了半天,load的过程就是为了设置model得值!
三、into上一步return了一个new出来的RequestBuilder对象,因此这个into()方法是属于RequestBuilder对象的:
// RequestBuilder类
@NonNull
public ViewTarget into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
RequestOptions requestOptions = this.requestOptions;
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);
}
上面代码部分的return值得重点关注
3.1 buildImageViewTargetglideContext.buildImageViewTarget(view, transcodeClass),/*targetListener=*/ null,requestOptions
buildImageViewTarget方法位于GlideContext.class:
// GlideContext类
@NonNull
public ViewTarget buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
#ImageViewTargetFactory.class
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)) {
// load的as传的是Drawable.class,返回对应的对象
return (ViewTarget) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
}
load()方法中的 as传入的参数是 Drawable.class,也就是说,这里会return一个DrawableImageViewTarget对象。
DrawableImageViewTarget的父类ImageViewTarget#onLoadStarted()会为view提前设置一些状态(如placeholder信息等),然后等待Engine后续的加载完成
// ImageViewTarget#onLoadStarted
@Override
public void onLoadStarted(@Nullable Drawable placeholder) {
super.onLoadStarted(placeholder);
setResourceInternal(null);
setDrawable(placeholder);
}
@Override
public void setDrawable(Drawable drawable) {
view.setImageDrawable(drawable);
}
3.2 return的into方法
return的into方法如下:
// RequestBuilder类
private <Y extends Target> Y into(
@NonNull Y target,
@Nullable RequestListener targetListener,
@NonNull RequestOptions options) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
options = options.autoClone();
Request request = buildRequest(target, targetListener, options);
// 获取正在进行的Request请求
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);
// 将Request和View进行绑定
target.setRequest(request);
// track请求
requestManager.track(target, request);
return target;
}
这里要通过Request previous = target.getRequest();获取当前正在进行的Request请求。然后根据判断,进行不同的操作。
3.2.1 将Request和View进行绑定,并保存到tag这里有一点需要注意,即target指的是ViewTarget(联系多层方法调用及泛型即可得知)。下面我们看一下target.setRequest(request);
// ViewTarget#setRequest
// 对Request和View绑定
@Override
public void setRequest(@Nullable Request request) {
setTag(request);
}
// 将这层“绑定关系”保存在tag中
private void setTag(@Nullable Object tag) {
if (tagId == null) {
isTagUsedAtLeastOnce = true;
view.setTag(tag);
} else {
view.setTag(tagId, tag);
}
}
ViewTarget的setRequest方法,其实就是将Request和View进行绑定(相当于卡莉斯塔和牛头的关系),然后保存在View的tag中。做完这一步,就可以光明正大的执行requestManager.track(target, request);
3.2.2 track当前请求// RequestManager类
void track(@NonNull Target target, @NonNull Request request) {
// TargetTracker保存了由当前RequestManager处理的所有Target的集合
targetTracker.track(target);
// RequestTracker是针对所有的Request集合
requestTracker.runRequest(request);
}
TargetTracker和RequestTracker分别是对target和request做了一个管理。
重点关注一下runRequest()方法:
// RequestTracker类
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
由isPaused判断界面的状态,如果可见,就直接调用request#begin方法执行。否则,就添加到pendingRequests中,来保证Request不会被GC掉(request是WeakHashMap,需强引用防GC)。
防不防GC不重要,重要的是这个request.begin()方法。Request是一个接口,需要看它的实现类SingleRequest(表示正确的请求类,其余还有缩略图请求协助类ThumbnailRequestCoordinator、错误请求协助类ErrorRequestCoordinator)。
也就是说,request.begin()调用的其实是SingleRequest类中的begin()方法:
// SingleRequest类
@Override
public void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
// 判断url是否为null
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) {
// 既然是去加载图片,就需要获取加载结果。
// SingleRequest类的接口ResourceCallback,将加载结果告诉Target,Target再去通知View该如何
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()方法会对url进行检查判断,如果为null就加载失败。如果size有效,就会触发真正的请求;否则就设置回调,等待有了size之后再去触发请求。
顺便一提, target.onLoadStarted(getPlaceholderDrawable()),这个onLoadStarted是接口类 Target中的方法,实现类是ViewTarget:
// ViewTarget类
// 调用的父类的onLoadStarted方法
@CallSuper
@Override
public void onLoadStarted(@Nullable Drawable placeholder) {
super.onLoadStarted(placeholder);
maybeAddAttachStateListener();
}
真正的请求是在onSizeReady()方法中发起的:
// SingleRequest类
@Override
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
if (IS_VERBOSE_LOGGABLE) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
// 判断状态是否是在等待size
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);
// 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()方法会对状态进行检查,判断是否是在等待size。接着会更新状态为Status.RUNNING,然后会调用Engine(包含了所有的参数信息,如缓存,图片显示等等),然后去开始真正请求,网络、内存、磁盘缓存等等。
结合3.1部分,Glide图片加载的执行流程就结束了。