Glide源码分析

Anna ·
更新时间:2024-09-21
· 787 次阅读

文章目录Glide的用法一、with二、load三、into3.1 buildImageViewTarget3.2 return的into方法3.2.1 将Request和View进行绑定,并保存到tag3.2.2 track当前请求 Glide的用法 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 三个步骤的源码进行分析了解。

一、with

Glide中的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()方法的参数来确定图片加载的生命周期。

二、load

with方法返回的是一个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 buildImageViewTarget glideContext.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图片加载的执行流程就结束了。


作者:墨玉浮白



glide

需要 登录 后方可回复, 如果你还没有账号请 注册新账号