Glide源码--执行流程

mac2025-05-30  1

Glide的基本使用

看一下郭神的博客,Android图片加载框架最全解析(八),带你全面了解Glide 4的用法

图片加载机制的基本流程

我们从这行代码看起

Glide.with(this).load(url).into(imageView);

1. with()

Glide会根据我们传入with()方法的参数来确定图片加载的生命周期。(避免消耗多余的资源,也避免在Activity销毁后加载图片从而导致空指针问题) 是Glide类中一组静态方法,有好几个方法重载,都是先调用RequestManagerRetriever的静态方法get()得到一个RequestManagerRetriever对象(此为单例),再调用这个实例的get()方法来获取RequestManager对象 RequestManagerFragment创建一个ActivityFragmentLifecycle实现了Lifecycle接口。所有的LifecycleListener会添加到一个集合中,当RequestManagerFragment生命周期方法触发时,会调用ActivityFragmentLifecycle相应生命周期方法,这个方法然后再遍历调用所有LifecycleListener的生命周期方法 RequestManager主要作用为实现request和Activity生命周期相关联,并且还实现了LifecycleListener接口来处理请求的生命周期

public class Glide { ... // RequestManager: 实现Glide加载资源的管理类,根据Activity生命周期管控资源加载请求,可以开启、暂停及重启。 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方法

RequestManagerRetriever # get()

private RequestManager getApplicationManager(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. // 通常,暂停/恢复由我们添加到fragment或activity中的fragment来处理。 // 但是,在这种情况下,由于附加到应用程序的管理器将不接收生命周期事件,我们必须强制管理器开始使用applicationlifecycle恢复。 applicationManager = new RequestManager(context.getApplicationContext(), new ApplicationLifecycle(), new EmptyRequestManagerTreeNode()); } } } return applicationManager; } public RequestManager get(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); } // 不在主线程就是调用应用程序管理器 public RequestManager get(FragmentActivity activity) { if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); // 不在主线程 } else { // 如果activity被摧毁,抛出异常 assertNotDestroyed(activity); FragmentManager fm = activity.getSupportFragmentManager(); return supportFragmentGet(activity, fm); } } public RequestManager get(Fragment fragment) { // fragment和activity未关联 if (fragment.getActivity() == null) { throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached"); } if (Util.isOnBackgroundThread()) { return get(fragment.getActivity().getApplicationContext()); } else { // getFragmentManager()所得到的是所在fragment 的父容器的管理器, // getChildFragmentManager()所得到的是在fragment 里面子容器的管理器。 FragmentManager fm = fragment.getChildFragmentManager(); return supportFragmentGet(fragment.getActivity(), fm); } } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public RequestManager get(Activity activity) { if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); android.app.FragmentManager fm = activity.getFragmentManager(); return fragmentGet(activity, fm); } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) private static void assertNotDestroyed(Activity activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) { throw new IllegalArgumentException("You cannot start a load for a destroyed activity"); } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public RequestManager get(android.app.Fragment fragment) { if (fragment.getActivity() == null) { throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached"); } if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { return get(fragment.getActivity().getApplicationContext()); } else { android.app.FragmentManager fm = fragment.getChildFragmentManager(); return fragmentGet(fragment.getActivity(), fm); } }

android.app.Fragment:使用getFragmentManager()方法。 android.support.v4.app.Fragment:使用getSupportFragmentManager()方法。

走的非Application方法,最终都调用如下两个方法:

RequestManagerRetriever # fragmentGet()

添加android.app.Fragment

@TargetApi(Build.VERSION_CODES.HONEYCOMB) RequestManager fragmentGet(Context context, android.app.FragmentManager fm) { // 在当前activity中创建一个隐藏的fragment并add到当前activity中 // RequestManagerFragment继承Fragment RequestManagerFragment current = getRequestManagerFragment(fm); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode()); // 将requestManager与fragment绑定 current.setRequestManager(requestManager); } return requestManager; } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) { RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); if (current == null) { current = pendingRequestManagerFragments.get(fm); if (current == null) { current = new RequestManagerFragment(); pendingRequestManagerFragments.put(fm, current); // 在当前activity中创建一个隐藏的fragment并add到当前activity中 fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current; }

RequestManagerRetriever # supportFragmentGet()

添加v4包的Fragment

RequestManager supportFragmentGet(Context context, FragmentManager fm) { SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode()); current.setRequestManager(requestManager); } return requestManager; } SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm) { SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag( FRAGMENT_TAG); if (current == null) { current = pendingSupportRequestManagerFragments.get(fm); if (current == null) { current = new SupportRequestManagerFragment(); pendingSupportRequestManagerFragments.put(fm, current); fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current; }

以上get()方法的重载可以分为两种情况:传入Application类型的参数和传入非Application类型的参数

Application类型的参数

调用带有Context参数的get()方法重载,然后调用getApplicationManager()来获取RequestManager对象(应用程序管理器)。 这是最简单的一种情况,因为Application对象的生命周期即应用程序的生命周期,Glide不需要做什么特殊处理,它自动是和应用程序的生命周期是同步的,应用程序关闭,Glide加载也会同时终止

非Application类型的参数

如果不在主线程或者Android SDK版本过低,走的还是传入Application的方法。 不管是Activity、Fragment还是FragmentActivity,最终流程都是一样的,那就是会向当前Activity当中添加一个隐藏的Fragment。因为Glide需要知道加载的生命周期。可是Glide并没有办法知道Activity的生命周期,于是Glide就使用了添加隐藏Fragment的这种小技巧,因为Fragment的生命周期和Activity是同步的,如果Activity被销毁了,Fragment是可以监听到的,这样Glide就可以捕获这个事件并停止图片加载了。

2. load()

Glide是支持图片URL字符串、图片本地路径等等加载形式的,因此RequestManager中也有很多个load()方法的重载。 先来看加载图片URL字符串的load()方法。

/** * Returns a request builder to load the given {@link java.lang.String}. * signature. * * @see #fromString() * @see #load(Object) * * @param string A file path, or a uri or url handled by {@link com.bumptech.glide.load.model.UriLoader}. */ public DrawableTypeRequest<String> load(String string) { return (DrawableTypeRequest<String>) fromString().load(string); } /** * Returns a request builder that loads data from {@link String}s using an empty signature. * * <p> * Note - this method caches data using only the given String as the cache key. If the data is a Uri outside of * your control, or you otherwise expect the data represented by the given String to change without the String * identifier changing, Consider using * {@link com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)} to mixin a signature * you create that identifies the data currently at the given String that will invalidate the cache if that data * changes. Alternatively, using {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} and/or * {@link com.bumptech.glide.DrawableRequestBuilder#skipMemoryCache(boolean)} may be appropriate. * </p> * * @see #from(Class) * @see #load(String) */ public DrawableTypeRequest<String> fromString() { return loadGeneric(String.class); } // 主要方法 private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) { // 获得ModelLoader对象 // 用于将任意复杂数据模型转换为可使用的具体数据类型 // 通过{@link datafetcher}获取模型所表示的资源的数据 ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context); ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader = Glide.buildFileDescriptorModelLoader(modelClass, context); if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) { throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for" + " which there is a registered ModelLoader, if you are using a custom model, you must first call" + " Glide#register with a ModelLoaderFactory for your custom model class"); } return optionsApplier.apply( new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context, glide, requestTracker, lifecycle, optionsApplier)); }

ModelLoader对象是用于加载图片的,而我们给load()方法传入不同类型的参数,这里也会得到不同的ModelLoader对象。由于刚才传进的参数是String.class,所以buildStreamModelLoader()方法最后得到的是StreamStringLoader对象(实现ModelLoader接口) 在loadGeneric方法的最后new了一个DrawableTypeRequest对象。

DrawableTypeRequest

提供了asBitmap()(强制指定加载静态图片)和asGif()两个方法,它们分别创建了一个BitmapTypeRequest和GifTypeRequest,如果没有强制指定,默认使用DrawableTypeRequest

// 用于创建加载请求的类,该类可以直接加载动画gif绘图文件或位图绘图文件, // 或者添加{@link com.bumptech.glide.load.resource.transcode.resourcetocoder}以将数据转换为{@link android.graphics.drawable.drawable}以外的资源类型。 public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions { private final ModelLoader<ModelType, InputStream> streamModelLoader; private final ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader; private final RequestManager.OptionsApplier optionsApplier; private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide, ModelLoader<A, InputStream> streamModelLoader, ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass, Class<R> transcodedClass, ResourceTranscoder<Z, R> transcoder) { if (streamModelLoader == null && fileDescriptorModelLoader == null) { return null; } if (transcoder == null) { transcoder = glide.buildTranscoder(resourceClass, transcodedClass); } DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class, resourceClass); ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader, fileDescriptorModelLoader); return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider); } DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader, ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide, RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) { super(context, modelClass, buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class, GlideDrawable.class, null), glide, requestTracker, lifecycle); this.streamModelLoader = streamModelLoader; this.fileDescriptorModelLoader = fileDescriptorModelLoader; this.optionsApplier = optionsApplier; } /** * Attempts to always load the resource as a {@link android.graphics.Bitmap}, even if it could actually be animated. * * @return A new request builder for loading a {@link android.graphics.Bitmap} */ public BitmapTypeRequest<ModelType> asBitmap() { return optionsApplier.apply(new BitmapTypeRequest<ModelType>(this, streamModelLoader, fileDescriptorModelLoader, optionsApplier)); } /** * Attempts to always load the resource as a {@link com.bumptech.glide.load.resource.gif.GifDrawable}. * <p> * If the underlying data is not a GIF, this will fail. As a result, this should only be used if the model * represents an animated GIF and the caller wants to interact with the GIfDrawable directly. Normally using * just an {@link com.bumptech.glide.DrawableTypeRequest} is sufficient because it will determine whether or * not the given data represents an animated GIF and return the appropriate animated or not animated * {@link android.graphics.drawable.Drawable} automatically. * </p> * * @return A new request builder for loading a {@link com.bumptech.glide.load.resource.gif.GifDrawable}. */ public GifTypeRequest<ModelType> asGif() { return optionsApplier.apply(new GifTypeRequest<ModelType>(this, streamModelLoader, optionsApplier)); } /** * {@inheritDoc} */ public <Y extends Target<File>> Y downloadOnly(Y target) { return getDownloadOnlyRequest().downloadOnly(target); } /** * {@inheritDoc} */ public FutureTarget<File> downloadOnly(int width, int height) { return getDownloadOnlyRequest().downloadOnly(width, height); } private GenericTranscodeRequest<ModelType, InputStream, File> getDownloadOnlyRequest() { return optionsApplier.apply(new GenericTranscodeRequest<ModelType, InputStream, File>(File.class, this, streamModelLoader, InputStream.class, File.class, optionsApplier)); } }

再次回到RequestManager的load方法,fromString()方法会返回一个DrawableTypeRequest对象,接下来调用这个对象的load()方法,可是上面DrawableTypeRequest的源码中并没有load方法,因此应该是在它的父类DrawableRequestBuilder中。

DrawableRequestBuilder

public class DrawableRequestBuilder<ModelType> extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable> implements BitmapOptions, DrawableOptions { DrawableRequestBuilder(Context context, Class<ModelType> modelClass, LoadProvider<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable> loadProvider, Glide glide, RequestTracker requestTracker, Lifecycle lifecycle) { super(context, modelClass, loadProvider, GlideDrawable.class, glide, requestTracker, lifecycle); // Default to animating. crossFade(); } /** * Loads and displays the {@link GlideDrawable} retrieved by the given thumbnail request if it finishes before this * request. Best used for loading thumbnail {@link GlideDrawable}s that are smaller and will be loaded more quickly * than the fullsize {@link GlideDrawable}. There are no guarantees about the order in which the requests will * actually finish. However, if the thumb request completes after the full request, the thumb {@link GlideDrawable} * will never replace the full image. * * @see #thumbnail(float) * * <p> * Note - Any options on the main request will not be passed on to the thumbnail request. For example, if * you want an animation to occur when either the full {@link GlideDrawable} loads or the thumbnail loads, * you need to call {@link #animate(int)} on both the thumb and the full request. For a simpler thumbnail * option where these options are applied to the humbnail as well, see {@link #thumbnail(float)}. * </p> * * <p> * Only the thumbnail call on the main request will be obeyed, recursive calls to this method are ignored. * </p> * * @param thumbnailRequest The request to use to load the thumbnail. * @return This builder object. */ public DrawableRequestBuilder<ModelType> thumbnail( DrawableRequestBuilder<?> thumbnailRequest) { super.thumbnail(thumbnailRequest); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> thumbnail( GenericRequestBuilder<?, ?, ?, GlideDrawable> thumbnailRequest) { super.thumbnail(thumbnailRequest); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> thumbnail(float sizeMultiplier) { super.thumbnail(sizeMultiplier); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> sizeMultiplier(float sizeMultiplier) { super.sizeMultiplier(sizeMultiplier); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> decoder(ResourceDecoder<ImageVideoWrapper, GifBitmapWrapper> decoder) { super.decoder(decoder); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> cacheDecoder(ResourceDecoder<File, GifBitmapWrapper> cacheDecoder) { super.cacheDecoder(cacheDecoder); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> encoder(ResourceEncoder<GifBitmapWrapper> encoder) { super.encoder(encoder); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> priority(Priority priority) { super.priority(priority); return this; } /** * Transform {@link GlideDrawable}s using the given * {@link com.bumptech.glide.load.resource.bitmap.BitmapTransformation}s. * * <p> * Note - Bitmap transformations will apply individually to each frame of animated GIF images and also to * individual {@link Bitmap}s. * </p> * * @see #centerCrop() * @see #fitCenter() * @see #bitmapTransform(com.bumptech.glide.load.Transformation[]) * @see #transform(com.bumptech.glide.load.Transformation[]) * * @param transformations The transformations to apply in order. * @return This request builder. */ public DrawableRequestBuilder<ModelType> transform(BitmapTransformation... transformations) { return bitmapTransform(transformations); } /** * Transform {@link GlideDrawable}s using {@link com.bumptech.glide.load.resource.bitmap.CenterCrop}. * * @see #fitCenter() * @see #transform(com.bumptech.glide.load.resource.bitmap.BitmapTransformation...) * @see #bitmapTransform(com.bumptech.glide.load.Transformation[]) * @see #transform(com.bumptech.glide.load.Transformation[]) * * @return This request builder. */ @SuppressWarnings("unchecked") public DrawableRequestBuilder<ModelType> centerCrop() { return transform(glide.getDrawableCenterCrop()); } /** * Transform {@link GlideDrawable}s using {@link com.bumptech.glide.load.resource.bitmap.FitCenter}. * * @see #centerCrop() * @see #transform(com.bumptech.glide.load.resource.bitmap.BitmapTransformation...) * @see #bitmapTransform(com.bumptech.glide.load.Transformation[]) * @see #transform(com.bumptech.glide.load.Transformation[]) * * @return This request builder. */ @SuppressWarnings("unchecked") public DrawableRequestBuilder<ModelType> fitCenter() { return transform(glide.getDrawableFitCenter()); } /** * Transform {@link GlideDrawable}s using the given {@link android.graphics.Bitmap} transformations. Replaces any * previous transformations. * * @see #fitCenter() * @see #centerCrop() * @see #transform(com.bumptech.glide.load.resource.bitmap.BitmapTransformation...) * @see #transform(com.bumptech.glide.load.Transformation[]) * * @return This request builder. */ public DrawableRequestBuilder<ModelType> bitmapTransform(Transformation<Bitmap>... bitmapTransformations) { GifBitmapWrapperTransformation[] transformations = new GifBitmapWrapperTransformation[bitmapTransformations.length]; for (int i = 0; i < bitmapTransformations.length; i++) { transformations[i] = new GifBitmapWrapperTransformation(glide.getBitmapPool(), bitmapTransformations[i]); } return transform(transformations); } /** * {@inheritDoc} * * @see #bitmapTransform(com.bumptech.glide.load.Transformation[]) * @see #centerCrop() * @see #fitCenter() */ @Override public DrawableRequestBuilder<ModelType> transform(Transformation<GifBitmapWrapper>... transformation) { super.transform(transformation); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> transcoder( ResourceTranscoder<GifBitmapWrapper, GlideDrawable> transcoder) { super.transcoder(transcoder); return this; } /** * {@inheritDoc} */ public final DrawableRequestBuilder<ModelType> crossFade() { super.animate(new DrawableCrossFadeFactory<GlideDrawable>()); return this; } /** * {@inheritDoc} */ public DrawableRequestBuilder<ModelType> crossFade(int duration) { super.animate(new DrawableCrossFadeFactory<GlideDrawable>(duration)); return this; } /** * {@inheritDoc} */ @Deprecated public DrawableRequestBuilder<ModelType> crossFade(Animation animation, int duration) { super.animate(new DrawableCrossFadeFactory<GlideDrawable>(animation, duration)); return this; } /** * {@inheritDoc} */ public DrawableRequestBuilder<ModelType> crossFade(int animationId, int duration) { super.animate(new DrawableCrossFadeFactory<GlideDrawable>(context, animationId, duration)); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> dontAnimate() { super.dontAnimate(); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> animate(ViewPropertyAnimation.Animator animator) { super.animate(animator); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> animate(int animationId) { super.animate(animationId); return this; } /** * {@inheritDoc} */ @Deprecated @SuppressWarnings("deprecation") @Override public DrawableRequestBuilder<ModelType> animate(Animation animation) { super.animate(animation); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> placeholder(int resourceId) { super.placeholder(resourceId); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> placeholder(Drawable drawable) { super.placeholder(drawable); return this; } @Override public DrawableRequestBuilder<ModelType> fallback(Drawable drawable) { super.fallback(drawable); return this; } @Override public DrawableRequestBuilder<ModelType> fallback(int resourceId) { super.fallback(resourceId); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> error(int resourceId) { super.error(resourceId); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> error(Drawable drawable) { super.error(drawable); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> listener( RequestListener<? super ModelType, GlideDrawable> requestListener) { super.listener(requestListener); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> diskCacheStrategy(DiskCacheStrategy strategy) { super.diskCacheStrategy(strategy); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> skipMemoryCache(boolean skip) { super.skipMemoryCache(skip); return this; } /** * {@inheritDoc} */ @Override public DrawableRequestBuilder<ModelType> override(int width, int height) { super.override(width, height); return this; } // ... @Override public DrawableRequestBuilder<ModelType> load(ModelType model) { // 父类的load()设置一些参数值 super.load(model); return this; } @Override public DrawableRequestBuilder<ModelType> clone() { return (DrawableRequestBuilder<ModelType>) super.clone(); } /** * {@inheritDoc} * * <p> * Note - If no transformation is set for this load, a default transformation will be applied based on the * value returned from {@link android.widget.ImageView# getScaleType()}. To avoid this default transformation, * use {@link #dontTransform()}. * </p> * * @param view {@inheritDoc} * @return {@inheritDoc} */ // 默认转换是ImageView# getScaleType(),不用默认转换dontTransform() @Override public Target<GlideDrawable> into(ImageView view) { return super.into(view); } @Override void applyFitCenter() { fitCenter(); } @Override void applyCenterCrop() { centerCrop(); } }

里面的很多方法比如placeholder()、error()、diskCacheStrategy()方法等是我们经常用到过的,这些就是Glide的绝大多数API了。 最终load()方法就是返回一个DrawableTypeRequest对象。

3. into()

最主要的部分。刚刚在DrawableRequestBuilder类中出现了into方法,里面只有一句super.into(view),我们来看它的父类GenericRequestBuilder中的into方法。

总体逻辑

GenericRequestBuilder # into()

/** * Sets the {@link ImageView} the resource will be loaded into, cancels any existing loads into the view, and frees * any resources Glide may have previously loaded into the view so they may be reused. * * @see Glide#clear(android.view.View) * * @param view The view to cancel previous loads for and load the new resource into. * @return The {@link com.bumptech.glide.request.target.Target} used to wrap the given {@link ImageView}. */ // public Target<TranscodeType> into(ImageView view) { Util.assertMainThread(); if (view == null) { throw new IllegalArgumentException("You must pass in a non null View"); } if (!isTransformationSet && view.getScaleType() != null) { switch (view.getScaleType()) { case CENTER_CROP: applyCenterCrop(); break; case FIT_CENTER: case FIT_START: case FIT_END: applyFitCenter(); break; //$CASES-OMITTED$ default: // Do nothing. } } return into(glide.buildImageViewTarget(view, transcodeClass)); }

transform后面再说,先来看最后一行代码,先是调用glide.buildImageViewTarget方法。

Glide # buildImageViewTarget()

创建的Target对象是用来最终展示图片。

<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) { return imageViewTargetFactory.buildTarget(imageView, transcodedClass); }

把我们传入的imageView包装成一个Target。

ImageViewTargetFactory # buildTarget()

创建并返回与图片来源对应的imageViewTarget。buildTarget()方法会根据传入的class参数来构建不同的Target对象。class参数基本只有两种情况,如果使用Glide加载图片的时候调用了asBitmap(),那么这里就得到BitmapImageViewTarget对象,否则得到的都是GlideDrawableImageViewTarget对象。而DrawableImageViewTarget通常用不到。

public class ImageViewTargetFactory { // 工厂方法模式 @SuppressWarnings("unchecked") public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) { if (GlideDrawable.class.isAssignableFrom(clazz)) { return (Target<Z>) new GlideDrawableImageViewTarget(view); } else if (Bitmap.class.equals(clazz)) { return (Target<Z>) new BitmapImageViewTarget(view); } else if (Drawable.class.isAssignableFrom(clazz)) { return (Target<Z>) new DrawableImageViewTarget(view); } else { throw new IllegalArgumentException("Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)"); } } }

总结:也就是说glide.buildImageViewTarget方法最后返回的是GlideDrawableImageViewTarget对象,最后一行是把这个参数传入到了GenericRequestBuilder另一个接收Target对象的into()方法当中了。

GenericRequestBuilder # into()

/** * Set the target the resource will be loaded into. * * @see Glide#clear(com.bumptech.glide.request.target.Target) * * @param target The target to load the resource into. * @return The given target. */ // 设置资源将加载到的目标 public <Y extends Target<TranscodeType>> Y into(Y target) { Util.assertMainThread(); if (target == null) { throw new IllegalArgumentException("You must pass in a non null Target"); } // 确保数据来源已确定,即已经调用了load()方法 if (!isModelSet) { throw new IllegalArgumentException("You must first set a model (try #load())"); } Request previous = target.getRequest(); // 清理target之前的request if (previous != null) { previous.clear(); // 停止绑定到当前target的上一个request的图片请求处理 requestTracker.removeRequest(previous); previous.recycle(); } // 创建Request对象 Request request = buildRequest(target); // 与target进行绑定 target.setRequest(request); lifecycle.addListener(target); // 执行这个Request requestTracker.runRequest(request); return target; }

Request是用来发出加载图片请求的,它是非常关键的一个组件。 上述方法的步骤:

如果当前target中的request对象存在,则清空并终止这个request对象的执行创建新的request对象并与当前target绑定执行创建的图片处理请求request

在没有Glide之前,我们处理ListView中的图片加载其实是一件比较麻烦的事情。由于ListView中Item的复用机制,会导致网络图片加载的错位或者闪烁。那我们解决这个问题的办法也很简单,就是给当前的ImageView设置tag,这个tag可以是图片的URL等等。当从网络中获取到图片时判断这个ImageVIew中的tag是否是这个图片的URL,如果是就加载图片,如果不是则跳过。在有了Glide之后,我们处理ListView或者Recyclerview中的图片加载就很无脑了,根本不需要作任何多余的操作,直接正常使用就行了。这其中的原理是Glide给我们处理了这些判断,我们来看一下Glide内部是如何处理的:

可以看出本质还是setTag()和getTag()

@Override public Request getRequest() { Object tag = getTag(); Request request = null; if (tag != null) { if (tag instanceof Request) { request = (Request) tag; } else { throw new IllegalArgumentException("You must not call setTag() on a view Glide is targeting"); } } return request; } private void setTag(Object tag) { if (tagId == null) { isTagUsedAtLeastOnce = true; view.setTag(tag); } else { view.setTag(tagId, tag); } }

GenericRequestBuilder # buildRequest()

private Request buildRequest(Target<TranscodeType> target) { if (priority == null) { priority = Priority.NORMAL; } return buildRequestRecursive(target, null); } private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) { // 会针对是否有缩略图来创建不同尺寸的请求 // 缩略图采用的是ThumbnailRequestCoordinator类 // 缩略图可以使用RequestBuilder.thumbnail(…)方法来添加上。 if (thumbnailRequestBuilder != null) { 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()"); } // Recursive case: contains a potentially recursive thumbnail request builder. if (thumbnailRequestBuilder.animationFactory.equals(NoAnimation.getFactory())) { thumbnailRequestBuilder.animationFactory = animationFactory; } if (thumbnailRequestBuilder.priority == null) { thumbnailRequestBuilder.priority = getThumbnailPriority(); } if (Util.isValidDimensions(overrideWidth, overrideHeight) && !Util.isValidDimensions(thumbnailRequestBuilder.overrideWidth, thumbnailRequestBuilder.overrideHeight)) { thumbnailRequestBuilder.override(overrideWidth, overrideHeight); } ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator); Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator); // Guard against infinite recursion. isThumbnailBuilt = true; // Recursively generate thumbnail requests. Request thumbRequest = thumbnailRequestBuilder.buildRequestRecursive(target, coordinator); isThumbnailBuilt = false; coordinator.setRequests(fullRequest, thumbRequest); // ThumbnailRequestCoordinator 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, sizeMultiplier, priority, coordinator); Request thumbnailRequest = obtainRequest(target, thumbSizeMultiplier, getThumbnailPriority(), coordinator); coordinator.setRequests(fullRequest, thumbnailRequest); // ThumbnailRequestCoordinator return coordinator; } else { // Base case: no thumbnail. // 没有缩略图 return obtainRequest(target, sizeMultiplier, priority, parentCoordinator); } } // 通常情况下,通过这个方法来获得request private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority, RequestCoordinator requestCoordinator) { // 刚才在load()方法中调用的所有API都是在这里组装到Request对象当中的 return GenericRequest.obtain( loadProvider, model, signature, context, priority, target, sizeMultiplier, placeholderDrawable, placeholderId, errorPlaceholder, errorId, fallbackDrawable, fallbackResource, requestListener, requestCoordinator, glide.getEngine(), transformation, transcodeClass, isCacheable, animationFactory, overrideWidth, overrideHeight, diskCacheStrategy); }

GenericRequest # obtain()

由此可以看出obtain()方法最后得到的是一个GenericRequest对象

public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain( LoadProvider<A, T, Z, R> loadProvider, A model, Key signature, Context context, Priority priority, Target<R> target, float sizeMultiplier, Drawable placeholderDrawable, int placeholderResourceId, Drawable errorDrawable, int errorResourceId, Drawable fallbackDrawable, int fallbackResourceId, RequestListener<? super A, R> requestListener, RequestCoordinator requestCoordinator, Engine engine, Transformation<Z> transformation, Class<R> transcodeClass, boolean isMemoryCacheable, GlideAnimationFactory<R> animationFactory, int overrideWidth, int overrideHeight, DiskCacheStrategy diskCacheStrategy) { @SuppressWarnings("unchecked") GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll(); if (request == null) { request = new GenericRequest<A, T, Z, R>(); } // 主要是赋值,把传入的参数赋给GenericRequest的成员变量中 request.init(loadProvider, model, signature, context, priority, target, sizeMultiplier, placeholderDrawable, placeholderResourceId, errorDrawable, errorResourceId, fallbackDrawable, fallbackResourceId, requestListener, requestCoordinator, engine, transformation, transcodeClass, isMemoryCacheable, animationFactory, overrideWidth, overrideHeight, diskCacheStrategy); return request; }

到此,Request的创建就完成了,再回到之前的方法GenericRequestBuilder 的 into(),看request对象是怎么执行的,紧接着它里面的方法runRequest()

RequestTracker # runRequest()

入口,RequestTracker这个类是所有请求操作的真正处理者,所有Request的暂停取消执行操作都由RequestTracker来完成,它是RequestManager里面的成员变量。加载前

/** * Starts tracking the given request. */ public void runRequest(Request request) { // 请求set集合 requests.add(request); // 判断Glide当前是不是暂停状态 if (!isPaused) { // 执行request request.begin(); } else { // 如果是暂停状态先将request加入到执行队列中 // 暂停状态解除了再执行 pendingRequests.add(request); } }

GenericRequest # begin()

加载时

@Override public void begin() { startTime = LogTime.getLogTime(); // 这里的model就是我们第二步load()方法传入的图片URL地址 if (model == null) { onException(null); return; } status = Status.WAITING_FOR_SIZE; // 如果宽高尺寸已经确定(使用了override() API指定) if (Util.isValidDimensions(overrideWidth, overrideHeight)) { onSizeReady(overrideWidth, overrideHeight); } else { // 获取尺寸后也会调用onSizeReady() // 内部是根据ImageView的layout_width和layout_height值做一系列计算图片应该的宽高 target.getSize(this); } if (!isComplete() && !isFailed() && canNotifyStatusChanged()) { // 先显示loading占位图 target.onLoadStarted(getPlaceholderDrawable()); } if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("finished run method in " + LogTime.getElapsedMillis(startTime)); } }

onException()方法会调用setErrorPlaceholder方法。

private void setErrorPlaceholder(Exception e) { if (!canNotifyStatusChanged()) { return; } Drawable error = model == null ? getFallbackDrawable() : null; if (error == null) { error = getErrorDrawable(); } if (error == null) { error = getPlaceholderDrawable(); } // 将占位图传入 target.onLoadFailed(e, error); }

这个方法先获取一个error占位图,如果获取不到再去获取一个loading占位图,再调用target.onLoadFailed,ImageViewTarget的这个方法就是把error这张占位图显示到imageview中。

GenericRequest # onSizeReady()

@Override public void onSizeReady(int width, int height) { if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime)); } if (status != Status.WAITING_FOR_SIZE) { return; } status = Status.RUNNING; width = Math.round(sizeMultiplier * width); height = Math.round(sizeMultiplier * height); ModelLoader<A, T> modelLoader = loadProvider.getModelLoader(); // ① // ImageVideoFetcher final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height); // ② if (dataFetcher == null) { onException(new Exception("Failed to load model: \'" + model + "\'")); return; } ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder(); // ① if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime)); } loadedFromMemoryCache = true; // 将刚才获得的ImageVideoFetcher、GifBitmapWrapperDrawableTranscoder等等一系列值都传进去 loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder, priority, isMemoryCacheable, diskCacheStrategy, this); // ③ loadedFromMemoryCache = resource != null; if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime)); } }

先来看loadProvider是什么,回到源头,先回到第二步load()方法,它最后返回的是DrawableTypeRequest对象,我们现在来分析一下它的构造函数

1. DrawableTypeRequest

buildProvider()方法中的streamModelLoader, fileDescriptorModelLoader都是loadGeneric()方法中构建出来的

DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader, ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide, RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) { super(context, modelClass, buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class, GlideDrawable.class, null), glide, requestTracker, lifecycle); this.streamModelLoader = streamModelLoader; this.fileDescriptorModelLoader = fileDescriptorModelLoader; this.optionsApplier = optionsApplier; }

DrawableTypeRequest # buildProvider()

private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide, ModelLoader<A, InputStream> streamModelLoader, ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass, Class<R> transcodedClass, ResourceTranscoder<Z, R> transcoder) { if (streamModelLoader == null && fileDescriptorModelLoader == null) { return null; } if (transcoder == null) { // glide.buildTranscoder用来构建一个ResourceTranscoder,它是用于对图片进行转码的 // ResourceTranscoder是一个接口,这里实际会构建出一个GifBitmapWrapperDrawableTranscoder对象 transcoder = glide.buildTranscoder(resourceClass, transcodedClass); } // glide.buildDataProvider用来构建一个DataLoadProvider,它是用于对图片进行编解码的 // DataLoadProvider也是一个接口,实际会构建出一个ImageVideoGifDrawableLoadProvider对象 DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class, resourceClass); // 把之前loadGeneric()方法中构建的两个ModelLoader封装到了ImageVideoModelLoader中 ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader, fileDescriptorModelLoader); // 把刚才构建出来的GifBitmapWrapperDrawableTranscoder、ImageVideoGifDrawableLoadProvider、ImageVideoModelLoader都封装进去 return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider); }

最后返回的这个FixedLoadProvider就是onSizeReady()中的loadProvider。 再回到onSizeReady()方法,看loadProvider.getModelLoader()和getTranscoder(),它们得到的对象就是刚才我们分析的ImageVideoModelLoader和GifBitmapWrapperDrawableTranscoder

2. ImageVideoModelLoader # getResourceFetcher()

得到的是一个ImageVideoFetcher

@Override public DataFetcher<ImageVideoWrapper> getResourceFetcher(A model, int width, int height) { DataFetcher<InputStream> streamFetcher = null; if (streamLoader != null) { // 这个streamLoader就是在loadGeneric()中构建出来的StreamStringLoader(load()传入参数是string的话) // 这个方法会得到一个HttpUrlFetcher对象 streamFetcher = streamLoader.getResourceFetcher(model, width, height); } DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher = null; if (fileDescriptorLoader != null) { fileDescriptorFetcher = fileDescriptorLoader.getResourceFetcher(model, width, height); } if (streamFetcher != null || fileDescriptorFetcher != null) { // 将HttpUrlFetcher传入 return new ImageVideoFetcher(streamFetcher, fileDescriptorFetcher); } else { return null; } }

3. Engine # load()

大多数都是在处理缓存,EngineJob的主要作用是用来开启线程的,为后面的异步加载图片做准备

public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher, DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder, Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) { Util.assertMainThread(); long startTime = LogTime.getLogTime(); final String id = fetcher.getId(); // 这个 Key 用来标识一个请求,Key 相同的 Request 是等效的。可以看出这个 Key 有多个参数组成,只要其中一个参数不同,Key 就不同 EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(), loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(), transcoder, loadProvider.getSourceEncoder()); EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); if (cached != null) { cb.onResourceReady(cached); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from cache", startTime, key); } return null; } EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable); if (active != null) { cb.onResourceReady(active); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from active resources", startTime, key); } return null; } // 避免重复请求,因为如果多个请求如果是等效的,没有必要为它们去加载多次,而只需要加载结果到来时逐个通知它们一遍就好 EngineJob current = jobs.get(key); if (current != null) { current.addCallback(cb); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Added to existing load", startTime, key); } return new LoadStatus(cb, current); } // 构建了一个EngineJob,它的主要作用是用来开启线程的,为后面的异步加载图片做准备 EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable); // DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation, transcoder, diskCacheProvider, diskCacheStrategy, priority); // EngineRunnable的manager就是EngineJob对象 EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority); jobs.put(key, engineJob); // engineJob.addCallback(cb); // 运行EngineRunnable对象,让它的run方法在子线程中执行(扔到线程池) engineJob.start(runnable); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Started new load", startTime, key); } return new LoadStatus(cb, engineJob); }

EngineRunnable # run()

得到Resource对象

@Override public void run() { if (isCancelled) { return; } Exception exception = null; Resource<?> resource = null; try { resource = decode(); // ① } catch (Exception e) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Exception decoding", e); } exception = e; } if (isCancelled) { if (resource != null) { resource.recycle(); } return; } if (resource == null) { onLoadFailed(exception); } else { onLoadComplete(resource); } }

EngineRunnable # decode()

private Resource<?> decode() throws Exception { // 从缓存中decode图片就会执行decodeFromCache if (isDecodingFromCache()) { return decodeFromCache(); } else { // 返回的是Resource<Z> return decodeFromSource(); // ① } }

EngineRunnable # decodeFromSource()

private Resource<?> decodeFromSource() throws Exception { return decodeJob.decodeFromSource(); }

DecodeJob # decodeFromSource()

public Resource<Z> decodeFromSource() throws Exception { Resource<T> decoded = decodeSource(); // 后面 return transformEncodeAndTranscode(decoded); } private Resource<T> decodeSource() throws Exception { Resource<T> decoded = null; try { long startTime = LogTime.getLogTime(); // fetcher就是刚才在onSizeReady()方法中得到的ImageVideoFetcher对象 final A data = fetcher.loadData(priority); // ① if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Fetched data", startTime); } if (isCancelled) { return null; } // 把返回的ImageVideoWrapper对象传入 decoded = decodeFromSourceData(data); // ② } finally { fetcher.cleanup(); } return decoded; }

1. ImageVideoModelLoader.ImageVideoFetcher # loadData()

返回ImageVideoWrapper对象

@SuppressWarnings("resource") // @see ModelLoader.loadData @Override public ImageVideoWrapper loadData(Priority priority) throws Exception { // priority表示load优先级 InputStream is = null; if (streamFetcher != null) { try { // 这里的streamFetcher是刚才在组装ImageVideoFetcher对象传进来的HttpUrlFetcher,这里开始真正的网络请求 is = streamFetcher.loadData(priority); // ① } catch (Exception e) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Exception fetching input stream, trying ParcelFileDescriptor", e); } if (fileDescriptorFetcher == null) { throw e; } } } ParcelFileDescriptor fileDescriptor = null; if (fileDescriptorFetcher != null) { try { fileDescriptor = fileDescriptorFetcher.loadData(priority); } catch (Exception e) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Exception fetching ParcelFileDescriptor", e); } if (is == null) { throw e; } } } // 把网络请求获取的InputStream传进去,返回上一层 return new ImageVideoWrapper(is, fileDescriptor); }

HttpUrlFetcher # loadData()

网络请求的入口,返回InputStream,服务器返回的数据在哪开始读呢?返回到ImageVideoFetcher的loadData()方法里

@Override public InputStream loadData(Priority priority) throws Exception { return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders()); } private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException { if (redirects >= MAXIMUM_REDIRECTS) { throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!"); } else { // Comparing the URLs using .equals performs additional network I/O and is generally broken. // See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html. try { if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) { throw new IOException("In re-direct loop"); } } catch (URISyntaxException e) { // Do nothing, this is best effort. } } urlConnection = connectionFactory.build(url); for (Map.Entry<String, String> headerEntry : headers.entrySet()) { urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue()); } urlConnection.setConnectTimeout(2500); urlConnection.setReadTimeout(2500); urlConnection.setUseCaches(false); urlConnection.setDoInput(true); // Connect explicitly to avoid errors in decoders if connection fails. urlConnection.connect(); if (isCancelled) { return null; } final int statusCode = urlConnection.getResponseCode(); if (statusCode / 100 == 2) { return getStreamForSuccessfulRequest(urlConnection); } else if (statusCode / 100 == 3) { String redirectUrlString = urlConnection.getHeaderField("Location"); if (TextUtils.isEmpty(redirectUrlString)) { throw new IOException("Received empty or null redirect url"); } URL redirectUrl = new URL(url, redirectUrlString); return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers); } else { if (statusCode == -1) { throw new IOException("Unable to retrieve response code from HttpUrlConnection."); } throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage()); } }

2. DecodeJob # decodeFromSourceData()

返回的是Resource对象,其实是Resource对象(else情况下)

private Resource<T> decodeFromSourceData(A data) throws IOException { final Resource<T> decoded; if (diskCacheStrategy.cacheSource()) { decoded = cacheAndDecodeSourceData(data); } else { long startTime = LogTime.getLogTime(); // 对图片进行解码 // loadProvider是刚才在onSizeReady()方法中得到的FixedLoadProvider // getSourceDecoder()会调用ImageVideoGifDrawableLoadProvider的getSourceDecoder() // 而getSourceDecoder()得到的则是一个GifBitmapWrapperResourceDecoder对象 decoded = loadProvider.getSourceDecoder().decode(data, width, height); // ① if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Decoded from source", startTime); } } return decoded; }

GifBitmapWrapperResourceDecoder # decode()

对图片进行解码

@SuppressWarnings("resource") // @see ResourceDecoder.decode @Override public Resource<GifBitmapWrapper> decode(ImageVideoWrapper source, int width, int height) throws IOException { ByteArrayPool pool = ByteArrayPool.get(); byte[] tempBytes = pool.getBytes(); GifBitmapWrapper wrapper = null; try { wrapper = decode(source, width, height, tempBytes); // } finally { pool.releaseBytes(tempBytes); } return wrapper != null ? new GifBitmapWrapperResource(wrapper) : null; } private GifBitmapWrapper decode(ImageVideoWrapper source, int width, int height, byte[] bytes) throws IOException { final GifBitmapWrapper result; if (source.getStream() != null) { result = decodeStream(source, width, height, bytes); // } else { result = decodeBitmapWrapper(source, width, height); } return result; } private GifBitmapWrapper decodeStream(ImageVideoWrapper source, int width, int height, byte[] bytes) throws IOException { InputStream bis = streamFactory.build(source.getStream(), bytes); bis.mark(MARK_LIMIT_BYTES); // 会先从流中读取2个字节的数据判断图片的类型 ImageHeaderParser.ImageType type = parser.parse(bis); bis.reset(); GifBitmapWrapper result = null; if (type == ImageHeaderParser.ImageType.GIF) { result = decodeGifWrapper(bis, width, height); } // Decoding the gif may fail even if the type matches. if (result == null) { // We can only reset the buffered InputStream, so to start from the beginning of the stream, we need to // pass in a new source containing the buffered stream rather than the original stream. ImageVideoWrapper forBitmapDecoder = new ImageVideoWrapper(bis, source.getFileDescriptor()); // 普通的静图 result = decodeBitmapWrapper(forBitmapDecoder, width, height); // ① } // 返回GifBitmapWrapper对象 return result; }

GifBitmapWrapperResourceDecoder # decodeBitmapWrapper()

private GifBitmapWrapper decodeBitmapWrapper(ImageVideoWrapper toDecode, int width, int height) throws IOException { GifBitmapWrapper result = null; // 这里的bitmapDecoder是一个ImageVideoBitmapDecoder对象 Resource<Bitmap> bitmapResource = bitmapDecoder.decode(toDecode, width, height); // ① if (bitmapResource != null) { result = new GifBitmapWrapper(bitmapResource, null); // ② } return result; }

ImageVideoBitmapDecoder # decode()

@SuppressWarnings("resource") // @see ResourceDecoder.decode @Override public Resource<Bitmap> decode(ImageVideoWrapper source, int width, int height) throws IOException { Resource<Bitmap> result = null; InputStream is = source.getStream(); if (is != null) { try { // streamDecoder是一个StreamBitmapDecoder对象 result = streamDecoder.decode(is, width, height); // 解码 ① } catch (IOException e) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Failed to load image from stream, trying FileDescriptor", e); } } } if (result == null) { ParcelFileDescriptor fileDescriptor = source.getFileDescriptor(); if (fileDescriptor != null) { result = fileDescriptorDecoder.decode(fileDescriptor, width, height); } } return result; } // StreamBitmapDecoder # decode() // 返回BitmapResource对象 @Override public Resource<Bitmap> decode(InputStream source, int width, int height) { Bitmap bitmap = downsampler.decode(source, bitmapPool, width, height, decodeFormat); // ① return BitmapResource.obtain(bitmap, bitmapPool); }

Downsampler # decode()

对服务器返回的InputStream的读取以及对图片的加载都在这里,进行了对图片的压缩、还有旋转、圆角等逻辑处理,返回的是bitmap对象,接下来就是让这个bitmap显示在界面上,回到上一步

/** * Load the image for the given InputStream. If a recycled Bitmap whose dimensions exactly match those of the image * for the given InputStream is available, the operation is much less expensive in terms of memory. * * <p> * Note - this method will throw an exception of a Bitmap with dimensions not matching * those of the image for the given InputStream is provided. * </p> * * @param is An {@link InputStream} to the data for the image. * @param pool A pool of recycled bitmaps. * @param outWidth The width the final image should be close to. * @param outHeight The height the final image should be close to. * @return A new bitmap containing the image from the given InputStream, or recycle if recycle is not null. */ // 为给定的inputstream加载图像。如果可以使用尺寸与给定inputstream的图像尺寸完全匹配的回收位图,则该操作在内存方面要便宜得多 @SuppressWarnings("resource") // see BitmapDecoder.decode @Override public Bitmap decode(InputStream is, BitmapPool pool, int outWidth, int outHeight, DecodeFormat decodeFormat) { final ByteArrayPool byteArrayPool = ByteArrayPool.get(); final byte[] bytesForOptions = byteArrayPool.getBytes(); final byte[] bytesForStream = byteArrayPool.getBytes(); final BitmapFactory.Options options = getDefaultOptions(); // Use to fix the mark limit to avoid allocating buffers that fit entire images. RecyclableBufferedInputStream bufferedStream = new RecyclableBufferedInputStream( is, bytesForStream); // Use to retrieve exceptions thrown while reading. // TODO(#126): when the framework no longer returns partially decoded Bitmaps or provides a way to determine // if a Bitmap is partially decoded, consider removing. ExceptionCatchingInputStream exceptionStream = ExceptionCatchingInputStream.obtain(bufferedStream); // Use to read data. // Ensures that we can always reset after reading an image header so that we can still attempt to decode the // full image even when the header decode fails and/or overflows our read buffer. See #283. MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream); try { exceptionStream.mark(MARK_POSITION); int orientation = 0; try { orientation = new ImageHeaderParser(exceptionStream).getOrientation(); } catch (IOException e) { if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Cannot determine the image orientation from header", e); } } finally { try { exceptionStream.reset(); } catch (IOException e) { if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Cannot reset the input stream", e); } } } options.inTempStorage = bytesForOptions; final int[] inDimens = getDimensions(invalidatingStream, bufferedStream, options); final int inWidth = inDimens[0]; final int inHeight = inDimens[1]; final int degreesToRotate = TransformationUtils.getExifOrientationDegrees(orientation); final int sampleSize = getRoundedSampleSize(degreesToRotate, inWidth, inHeight, outWidth, outHeight); // ① final Bitmap downsampled = downsampleWithSize(invalidatingStream, bufferedStream, options, pool, inWidth, inHeight, sampleSize, decodeFormat); // BitmapFactory swallows exceptions during decodes and in some cases when inBitmap is non null, may catch // and log a stack trace but still return a non null bitmap. To avoid displaying partially decoded bitmaps, // we catch exceptions reading from the stream in our ExceptionCatchingInputStream and throw them here. final Exception streamException = exceptionStream.getException(); if (streamException != null) { throw new RuntimeException(streamException); } Bitmap rotated = null; if (downsampled != null) { rotated = TransformationUtils.rotateImageExif(downsampled, pool, orientation); if (!downsampled.equals(rotated) && !pool.put(downsampled)) { downsampled.recycle(); } } return rotated; } finally { byteArrayPool.releaseBytes(bytesForOptions); byteArrayPool.releaseBytes(bytesForStream); exceptionStream.release(); releaseOptions(options); } } public int[] getDimensions(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream, BitmapFactory.Options options) { options.inJustDecodeBounds = true; decodeStream(is, bufferedStream, options); options.inJustDecodeBounds = false; return new int[] { options.outWidth, options.outHeight }; } // 压缩图片 private Bitmap downsampleWithSize(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream, BitmapFactory.Options options, BitmapPool pool, int inWidth, int inHeight, int sampleSize, DecodeFormat decodeFormat) { // Prior to KitKat, the inBitmap size must exactly match the size of the bitmap we're decoding. Bitmap.Config config = getConfig(is, decodeFormat); options.inSampleSize = sampleSize; options.inPreferredConfig = config; if ((options.inSampleSize == 1 || Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) && shouldUsePool(is)) { int targetWidth = (int) Math.ceil(inWidth / (double) sampleSize); int targetHeight = (int) Math.ceil(inHeight / (double) sampleSize); // BitmapFactory will clear out the Bitmap before writing to it, so getDirty is safe. setInBitmap(options, pool.getDirty(targetWidth, targetHeight, config)); } return decodeStream(is, bufferedStream, options); } private static Bitmap decodeStream(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream, BitmapFactory.Options options) { if (options.inJustDecodeBounds) { // This is large, but jpeg headers are not size bounded so we need something large enough to minimize // the possibility of not being able to fit enough of the header in the buffer to get the image size so // that we don't fail to load images. The BufferedInputStream will create a new buffer of 2x the // original size each time we use up the buffer space without passing the mark so this is a maximum // bound on the buffer size, not a default. Most of the time we won't go past our pre-allocated 16kb. is.mark(MARK_POSITION); } else { // 一旦我们读取了图像头,就不再需要允许缓冲区扩大大小。避免 // 读取图像数据的不必要分配,我们修复标记限制,使其不大于 // 当前缓冲区大小。 // Once we've read the image header, we no longer need to allow the buffer to expand in size. To avoid // unnecessary allocations reading image data, we fix the mark limit so that it is no larger than our // current buffer size here. See issue #225. bufferedStream.fixMarkLimit(); } final Bitmap result = BitmapFactory.decodeStream(is, null, options); try { if (options.inJustDecodeBounds) { is.reset(); } } catch (IOException e) { if (Log.isLoggable(TAG, Log.ERROR)) { Log.e(TAG, "Exception loading inDecodeBounds=" + options.inJustDecodeBounds + " sample=" + options.inSampleSize, e); } } return result; }

BitmapResource

把bitmap对象包装成了BitmapResource对象,如果我们想获取bitmap,只需要调用Resource的get()方法

public class BitmapResource implements Resource<Bitmap> { private final Bitmap bitmap; private final BitmapPool bitmapPool; /** * Returns a new {@link BitmapResource} wrapping the given {@link Bitmap} if the Bitmap is non-null or null if the * given Bitmap is null. * * @param bitmap A Bitmap. * @param bitmapPool A non-null {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool}. */ public static BitmapResource obtain(Bitmap bitmap, BitmapPool bitmapPool) { if (bitmap == null) { return null; } else { return new BitmapResource(bitmap, bitmapPool); } } public BitmapResource(Bitmap bitmap, BitmapPool bitmapPool) { if (bitmap == null) { throw new NullPointerException("Bitmap must not be null"); } if (bitmapPool == null) { throw new NullPointerException("BitmapPool must not be null"); } this.bitmap = bitmap; this.bitmapPool = bitmapPool; } @Override public Bitmap get() { return bitmap; } @Override public int getSize() { return Util.getBitmapByteSize(bitmap); } @Override public void recycle() { if (!bitmapPool.put(bitmap)) { bitmap.recycle(); } } }

我们一步步返回,最后将Resource返回到GifBitmapWrapperResourceDecoder的decodeBitmapWrapper()方法。

private GifBitmapWrapper decodeBitmapWrapper(ImageVideoWrapper toDecode, int width, int height) throws IOException { GifBitmapWrapper result = null; Resource<Bitmap> bitmapResource = bitmapDecoder.decode(toDecode, width, height); if (bitmapResource != null) { // 将Resource<Bitmap>封装到GifBitmapWrapper中 result = new GifBitmapWrapper(bitmapResource, null); } return result; }

这个GifBitmapWrapper既能封装GIF,又能封装Bitmap,保证不管是什么类型的图片Glide都能从容应对。 GifBitmapWrapper就是分别对gifResource和bitmapResource做了一层封装

再进行返回到GifBitmapWrapperResourceDecoder最外层的decode(),会再进行一次封装。 封装成GifBitmapWrapperResource,最终返回的是Resource对象。这个GifBitmapWrapperResource和刚才的BitmapResource是相似的,都实现的Resource接口,都可以通过get()方法来获取封装起来的具体内容

@Override public Resource<GifBitmapWrapper> decode(ImageVideoWrapper source, int width, int height) throws IOException { ByteArrayPool pool = ByteArrayPool.get(); byte[] tempBytes = pool.getBytes(); GifBitmapWrapper wrapper = null; try { // 返回的GifBitmapWrapper对象 wrapper = decode(source, width, height, tempBytes); } finally { pool.releaseBytes(tempBytes); } return wrapper != null ? new GifBitmapWrapperResource(wrapper) : null; // ① }

GifBitmapWrapperResource

public class GifBitmapWrapperResource implements Resource<GifBitmapWrapper> { private final GifBitmapWrapper data; public GifBitmapWrapperResource(GifBitmapWrapper data) { if (data == null) { throw new NullPointerException("Data must not be null"); } this.data = data; } @Override public GifBitmapWrapper get() { return data; } @Override public int getSize() { return data.getSize(); } @Override public void recycle() { Resource<Bitmap> bitmapResource = data.getBitmapResource(); if (bitmapResource != null) { bitmapResource.recycle(); } Resource<GifDrawable> gifDataResource = data.getGifResource(); if (gifDataResource != null) { gifDataResource.recycle(); } } }

最终回到DecodeJob中的decodeFromSource()

public Resource<Z> decodeFromSource() throws Exception { // Resource<GifBitmapWrapper>对象 Resource<T> decoded = decodeSource(); // Resource<T>转成Resource<Z> return transformEncodeAndTranscode(decoded); // ① }

DecodeJob # transformEncodeAndTranscode()

返回Resource对象

private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) { long startTime = LogTime.getLogTime(); // Resource<T> transformed = transform(decoded); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Transformed resource from source", startTime); } writeTransformedToCache(transformed); startTime = LogTime.getLogTime(); // Resource<T>转成Resource<Z> ① // Resource<Z>就是Resource<GlideDrawable> Resource<Z> result = transcode(transformed); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Transcoded transformed from source", startTime); } return result; }

transcode()方法调用了transcoder的transcode()方法。transcoder是什么呢? 在第二步load()方法返回的那个DrawableTypeRequest对象,它的构建函数中去构建了一个FixedLoadProvider对象,然后我们将三个参数传入到了FixedLoadProvider当中,其中就有一个GifBitmapWrapperDrawableTranscoder对象。后来在onSizeReady()方法中获取到了这个参数,并传递到了Engine当中,然后又由Engine传递到了DecodeJob当中。所以也就是说transcoder就是GifBitmapWrapperDrawableTranscoder

GifBitmapWrapperDrawableTranscoder # transcode()

核心作用就是用来转码的,因为GifBitmapWrapper是无法直接显示到ImageView上面的,只有Bitmap或Drawable才能显示到ImageView上。这里transcode()先从Resource中取出GifBitmapWrapper对象,然后再从GifBitmapWrapper中取出Resource对象。如果Resource为空,说明此时加载的是GIF图,调用getGifResource()将图片取出(因为Glide用于加载GIF图片是使用的GifDrawable这个类,它本身就是一个Drawable对象了) 如果Resource不为空,需要再做一次转码,将Bitmap对象转换成Drawable对象才行(因为要保证静图和动图的类型一致性)

@SuppressWarnings("unchecked") @Override public Resource<GlideDrawable> transcode(Resource<GifBitmapWrapper> toTranscode) { GifBitmapWrapper gifBitmap = toTranscode.get(); Resource<Bitmap> bitmapResource = gifBitmap.getBitmapResource(); final Resource<? extends GlideDrawable> result; if (bitmapResource != null) { // 调用GlideBitmapDrawableTranscoder.transcode() result = bitmapDrawableResourceTranscoder.transcode(bitmapResource); // ① } else { result = gifBitmap.getGifResource(); } // This is unchecked but always safe, anything that extends a Drawable can be safely cast to a Drawable. return (Resource<GlideDrawable>) result; }

GlideBitmapDrawableTranscoder # transcode()

new了一个GlideBitmapDrawable对象,并把Bitmap封装到里面,再对GlideBitmapDrawable再进行一次封装,返回一个Resource对象

public class GlideBitmapDrawableTranscoder implements ResourceTranscoder<Bitmap, GlideBitmapDrawable> { private final Resources resources; private final BitmapPool bitmapPool; public GlideBitmapDrawableTranscoder(Context context) { this(context.getResources(), Glide.get(context).getBitmapPool()); } public GlideBitmapDrawableTranscoder(Resources resources, BitmapPool bitmapPool) { this.resources = resources; this.bitmapPool = bitmapPool; } @Override public Resource<GlideBitmapDrawable> transcode(Resource<Bitmap> toTranscode) { GlideBitmapDrawable drawable = new GlideBitmapDrawable(resources, toTranscode.get()); return new GlideBitmapDrawableResource(drawable, bitmapPool); } ... }

现在再返回到GifBitmapWrapperDrawableTranscoder的transcode()方法中,发现不管是静图的Resource还是动图的Resource对象,它们都是属于父类Resource对象的,GifBitmapWrapperDrawableTranscoder的transcode()最后返回的就是Resource,这个就是转换后的Resource

一直向上返回到EngineRunnable的run()方法。

@Override public void run() { if (isCancelled) { return; } Exception exception = null; Resource<?> resource = null; try { // 获得到Resource<GlideDrawable> resource = decode(); } catch (Exception e) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Exception decoding", e); } exception = e; } if (isCancelled) { if (resource != null) { resource.recycle(); } return; } if (resource == null) { onLoadFailed(exception); } else { // 表示图片加载已经完成 onLoadComplete(resource); } }

EngineRunnable # onLoadComplete()

private void onLoadComplete(Resource resource) { // 这个manager就是EngineJob对象 manager.onResourceReady(resource); }

EngineJob # onResourceReady()

在onResourceReady()方法里使用handler发出了一条MSG_COMPLETE消息,然后在MainThreadCallback的handleMessage()中会收到这条消息,从这里又回到主线程,很快就更新UI。 handleResultOnMainThread()方法中又通过一个循环,调用了所有ResourceCallback的onResourceReady()方法。ResourceCallback是什么呢?在addCallback方法中(向cbs集合中去添加ResourceCallback)

class EngineJob implements EngineRunnable.EngineRunnableManager { private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback()); private final List<ResourceCallback> cbs = new ArrayList<ResourceCallback>(); ... public void addCallback(ResourceCallback cb) { Util.assertMainThread(); if (hasResource) { cb.onResourceReady(engineResource); } else if (hasException) { cb.onException(exception); } else { cbs.add(cb); } } @Override public void onResourceReady(final Resource<?> resource) { this.resource = resource; MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget(); } private void handleResultOnMainThread() { if (isCancelled) { resource.recycle(); return; } else if (cbs.isEmpty()) { throw new IllegalStateException("Received a resource without any callbacks to notify"); } engineResource = engineResourceFactory.build(resource, isCacheable); hasResource = true; engineResource.acquire(); listener.onEngineJobComplete(key, engineResource); for (ResourceCallback cb : cbs) { if (!isInIgnoredCallbacks(cb)) { engineResource.acquire(); // 不是此类中的 cb.onResourceReady(engineResource); } } engineResource.release(); } @Override public void onException(final Exception e) { this.exception = e; MAIN_THREAD_HANDLER.obtainMessage(MSG_EXCEPTION, this).sendToTarget(); } private void handleExceptionOnMainThread() { if (isCancelled) { return; } else if (cbs.isEmpty()) { throw new IllegalStateException("Received an exception without any callbacks to notify"); } hasException = true; listener.onEngineJobComplete(key, null); for (ResourceCallback cb : cbs) { if (!isInIgnoredCallbacks(cb)) { cb.onException(exception); } } } private static class MainThreadCallback implements Handler.Callback { @Override public boolean handleMessage(Message message) { if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) { EngineJob job = (EngineJob) message.obj; if (MSG_COMPLETE == message.what) { job.handleResultOnMainThread(); } else { job.handleExceptionOnMainThread(); } return true; } return false; } } ... }

addCallback()方法在Engine的load方法里面

public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedListener, EngineResource.ResourceListener { ... public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher, DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder, Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) { ... EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable); DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation, transcoder, diskCacheProvider, diskCacheStrategy, priority); EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority); jobs.put(key, engineJob); engineJob.addCallback(cb); engineJob.start(runnable); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Started new load", startTime, key); } return new LoadStatus(cb, engineJob); } ... }

这个cb参数是从哪传进来的?调用Engine的load方法是GenericRequest的onSizeReady()方法

public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback, ResourceCallback { ... @Override public void onSizeReady(int width, int height) { if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime)); } if (status != Status.WAITING_FOR_SIZE) { return; } status = Status.RUNNING; width = Math.round(sizeMultiplier * width); height = Math.round(sizeMultiplier * height); ModelLoader<A, T> modelLoader = loadProvider.getModelLoader(); final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height); if (dataFetcher == null) { onException(new Exception("Failed to load model: \'" + model + "\'")); return; } ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder(); if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime)); } loadedFromMemoryCache = true; // 最后一个参数传的this loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder, priority, isMemoryCacheable, diskCacheStrategy, this); loadedFromMemoryCache = resource != null; if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime)); } } ... }

GenericRequest本身就实现了ResourceCallback的接口,因此EngineJob的回调最终其实就是回调到了GenericRequest的onResourceReady()方法当中了

GenericRequest # onResourceReady()

第一个onResourceReady()方法当中调用resource.get()获取到了封装的图片对象,也就是GlideBitmapDrawable对象或者是GifDrawable对象,这个值传入到了第二个onResourceReady()方法中

/** * A callback method that should never be invoked directly. */ @SuppressWarnings("unchecked") @Override public void onResourceReady(Resource<?> resource) { if (resource == null) { onException(new Exception("Expected to receive a Resource<R> with an object of " + transcodeClass + " inside, but instead got null.")); return; } Object received = resource.get(); if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) { releaseResource(resource); onException(new Exception("Expected to receive an object of " + transcodeClass + " but instead got " + (received != null ? received.getClass() : "") + "{" + received + "}" + " inside Resource{" + resource + "}." + (received != null ? "" : " " + "To indicate failure return a null Resource object, " + "rather than a Resource object containing null data.") )); return; } if (!canSetResource()) { releaseResource(resource); // We can't set the status to complete before asking canSetResource(). status = Status.COMPLETE; return; } onResourceReady(resource, (R) received); } /** * Internal {@link #onResourceReady(Resource)} where arguments are known to be safe. * * @param resource original {@link Resource}, never <code>null</code> * @param result object returned by {@link Resource#get()}, checked for type and never <code>null</code> */ private void onResourceReady(Resource<?> resource, R result) { // We must call isFirstReadyResource before setting status. boolean isFirstResource = isFirstReadyResource(); status = Status.COMPLETE; this.resource = resource; if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache, isFirstResource)) { GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource); target.onResourceReady(result, animation);// ① } notifyLoadSuccess(); if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("Resource ready in " + LogTime.getElapsedMillis(startTime) + " size: " + (resource.getSize() * TO_MEGABYTE) + " fromCache: " + loadedFromMemoryCache); } }

这个target是什么?在第三步into()方法的最后一行,调用了glide.buildImageViewTarget()方法来构建出一个Target,而这个Target就是一个GlideDrawableImageViewTarget对象。

GlideDrawableImageViewTarget

public class GlideDrawableImageViewTarget extends ImageViewTarget<GlideDrawable> { private static final float SQUARE_RATIO_MARGIN = 0.05f; private int maxLoopCount; private GlideDrawable resource; public GlideDrawableImageViewTarget(ImageView view) { this(view, GlideDrawable.LOOP_FOREVER); } public GlideDrawableImageViewTarget(ImageView view, int maxLoopCount) { super(view); this.maxLoopCount = maxLoopCount; } @Override public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) { if (!resource.isAnimated()) { float viewRatio = view.getWidth() / (float) view.getHeight(); float drawableRatio = resource.getIntrinsicWidth() / (float) resource.getIntrinsicHeight(); if (Math.abs(viewRatio - 1f) <= SQUARE_RATIO_MARGIN && Math.abs(drawableRatio - 1f) <= SQUARE_RATIO_MARGIN) { resource = new SquaringDrawable(resource, view.getWidth()); } } super.onResourceReady(resource, animation); this.resource = resource; resource.setLoopCount(maxLoopCount); resource.start(); } @Override protected void setResource(GlideDrawable resource) { view.setImageDrawable(resource); } @Override public void onStart() { if (resource != null) { resource.start(); } } @Override public void onStop() { if (resource != null) { resource.stop(); } } }

里面的onResourceReady()方法中做了一些逻辑处理,包括如果是GIF图片的话,就调用resource.start()方法开始播放图片,但是好像并没有看到哪里有将GlideDrawable显示到ImageView上的逻辑。确实没有,不过父类里面有,这里调用了super.onResourceReady()方法。 GlideDrawableImageViewTarget的父类是ImageViewTarget

ImageViewTarget # onResourceReady()

public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements GlideAnimation.ViewAdapter { ... @Override public void onResourceReady(Z resource, GlideAnimation<? super Z> glideAnimation) { if (glideAnimation == null || !glideAnimation.animate(resource, this)) { setResource(resource); } } protected abstract void setResource(Z resource); }

ImageViewTarget的setResource()是一个抽象方法,具体的实现还在子类中,再来看一下GlideDrawableImageViewTarget的setResource()方法

GlideDrawableImageViewTarget # setResource()

@Override protected void setResource(GlideDrawable resource) { view.setImageDrawable(resource); }

至此,图片就显示到View上了

最新回复(0)