由于项目的需要,这几天对Glide的执行过程做了简单的了解,希望对想了解Glide基本用法的朋友能有所帮助。
注意
此系列博客基于Glide V3.7.0版本源码
这里假设朋友们能够在Android Studio中正确引入Glide相关的依赖,如果有不懂的朋友,请参考官方文档引入依赖。
为了让朋友们尽快的了解Glide加载图片的流程,我们就从最简单的方式入手。请看如下代码:
ImageView fullscreenView = (ImageView) findViewById(R.id.fullscreen_view); String imageUrl = "http://image.url.com"; Glide.with(this) .load(imageUrl) .into(fullscreenView);代码清单1-1
使用Glide加载图片就是这么简单!!!
然而,简单的背后往往隐藏了太多的未知数,那么现在我们就来看看这几行简单代码背后究竟隐藏了哪些奇妙的东西。现在就和博主一起开启Glide的学习之旅吧 :)
在上述代码清单1-1中,我是在FragmentActivity子类中调用了Glide的with方法,SO这里的this即是指FragmentActivity的子类实例。我们点击查看其源码,如下:
public static RequestManager with(FragmentActivity activity) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(activity); }首先获取一个RequestManagerRetriever实例,通过该实例得到RequestManager对象。我们现在进入RequestManagerRetriever#get(FragmentActivity)方法中来具体看看RequestManager的获取过程:
public RequestManager get(FragmentActivity activity) { if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); FragmentManager fm = activity.getSupportFragmentManager(); return supportFragmentGet(activity, fm); } }我们只考虑常规情况下使用的场景(不考虑缓存等情况,后文与此相同),由上面的代码,我们很容易定位到supportFragmentGet方法:
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; }由于我们是初次调用Glide加载图片,所以这里会创建一个新的RequestManager实例,并存入SupportRequestManagerFragment的current实例中。传入RequestManager对象中的Lifecycle和RequestManagerTreeNode我们后面再说。这里需要注意的是,在创建RequestManager对象时,默认创建了一个RequestTracker对象和OptionsApplier对象,以及我们的Glide对象。
我们进入到RequestManager的构造函数中,定位到glide实例的获取过程:
RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode, RequestTracker requestTracker, ConnectivityMonitorFactory factory) { this.context = context.getApplicationContext(); this.lifecycle = lifecycle; this.treeNode = treeNode; this.requestTracker = requestTracker; this.glide = Glide.get(context); this.optionsApplier = new OptionsApplier(); //省略其它无关代码 ........................... ........................... }在上述代码中,我们顺藤摸瓜,来到Glide类的get方法中:
public static Glide get(Context context) { if (glide == null) { synchronized (Glide.class) { if (glide == null) { Context applicationContext = context.getApplicationContext(); List<GlideModule> modules = new ManifestParser(applicationContext).parse(); GlideBuilder builder = new GlideBuilder(applicationContext); for (GlideModule module : modules) { module.applyOptions(applicationContext, builder); } glide = builder.createGlide(); for (GlideModule module : modules) { module.registerComponents(applicationContext, glide); } } } } return glide; }在获取Glide的实例过程中,我们看到Glide会从AndroidManifest.xml文件中查询我们注册的GlideModule。同时将GlideBuilder和Glide的实例传入我们注册的GlideModule的对应方法中。由此我们可以了解到,如果想预先控制Glide的一些行为,可以在我们的GlideModule的applyOtions和registerComponents方法中做控制。
接下来我们继续查看GlideBuilder的createGlide方法,直接定位到方法的最后一行:
new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);好了,重头戏该上演了,我们来看看Glide类的构造函数:
Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) { this.engine = engine; this.bitmapPool = bitmapPool; this.memoryCache = memoryCache; this.decodeFormat = decodeFormat; loaderFactory = new GenericLoaderFactory(context); mainHandler = new Handler(Looper.getMainLooper()); bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat); dataLoadProviderRegistry = new DataLoadProviderRegistry(); StreamBitmapDataLoadProvider streamBitmapLoadProvider = new StreamBitmapDataLoadProvider(bitmapPool, decodeFormat); dataLoadProviderRegistry.register(InputStream.class, Bitmap.class, streamBitmapLoadProvider); FileDescriptorBitmapDataLoadProvider fileDescriptorLoadProvider = new FileDescriptorBitmapDataLoadProvider(bitmapPool, decodeFormat); dataLoadProviderRegistry.register(ParcelFileDescriptor.class, Bitmap.class, fileDescriptorLoadProvider); ImageVideoDataLoadProvider imageVideoDataLoadProvider = new ImageVideoDataLoadProvider(streamBitmapLoadProvider, fileDescriptorLoadProvider); dataLoadProviderRegistry.register(ImageVideoWrapper.class, Bitmap.class, imageVideoDataLoadProvider); GifDrawableLoadProvider gifDrawableLoadProvider = new GifDrawableLoadProvider(context, bitmapPool); dataLoadProviderRegistry.register(InputStream.class, GifDrawable.class, gifDrawableLoadProvider); dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class, new ImageVideoGifDrawableLoadProvider(imageVideoDataLoadProvider, gifDrawableLoadProvider, bitmapPool)); dataLoadProviderRegistry.register(InputStream.class, File.class, new StreamFileDataLoadProvider()); register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory()); register(File.class, InputStream.class, new StreamFileLoader.Factory()); register(int.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory()); register(int.class, InputStream.class, new StreamResourceLoader.Factory()); register(Integer.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory()); register(Integer.class, InputStream.class, new StreamResourceLoader.Factory()); register(String.class, ParcelFileDescriptor.class, new FileDescriptorStringLoader.Factory()); register(String.class, InputStream.class, new StreamStringLoader.Factory()); register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory()); register(Uri.class, InputStream.class, new StreamUriLoader.Factory()); register(URL.class, InputStream.class, new StreamUrlLoader.Factory()); register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory()); register(byte[].class, InputStream.class, new StreamByteArrayLoader.Factory()); transcoderRegistry.register(Bitmap.class, GlideBitmapDrawable.class, new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool)); transcoderRegistry.register(GifBitmapWrapper.class, GlideDrawable.class, new GifBitmapWrapperDrawableTranscoder( new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool))); bitmapCenterCrop = new CenterCrop(bitmapPool); drawableCenterCrop = new GifBitmapWrapperTransformation(bitmapPool, bitmapCenterCrop); bitmapFitCenter = new FitCenter(bitmapPool); drawableFitCenter = new GifBitmapWrapperTransformation(bitmapPool, bitmapFitCenter); }这个方法相对比较长,但是理解起来较为简单。主要就是注册一些DataLoadProvider、ModelLoader的factory以及几个Transcoder。为了更直观的理解和查询,我将它们罗列成下面三张表:(PS:这三张表对于理解Glide的加载流程很重要)
表1-1 ModelType到DataType的映射表
IDModelClassResourceClassDataLoaderFactory1FileParcelFileDescriptorFileDescriptorFileLoader.Factory2FileInputStreamStreamFileLoader.Factory3intParcelFileDescriptorFileDescriptorResourceLoader.Factory4intInputStreamStreamResourceLoader.Factory5IntegerParcelFileDescriptorFileDescriptorResourceLoader.Factory6IntegerInputStreamStreamResourceLoader.Factory7StringParcelFileDescriptorFileDescriptorStringLoader.Factory8StringInputStreamStreamStringLoader.Factory9UriParcelFileDescriptorFileDescriptorUriLoader.Factory10UriInputStreamStreamUriLoader.Factory11URLInputStreamStreamUrlLoader.Factory12GlideUrlInputStreamHttpUrlGlideUrlLoader.Factory13byte[]InputStreamStreamByteArrayLoader.Factory14*[ModelType]ImageVideoWrapperImageVideoModelLoader注 编号( 14* )并不是在构造方法中直接注册的 factory 而是在 DrawableRequestBuidler中创建的一个 ModelLoader 。
表1-2 DataType到ResourceType的映射表
IDDataClassResourceClassDataLoadProvider1InputStreamBitmapStreamBitmapDataLoadProvider2ParcelFileDescriptorBitmapFileDescriptorBitmapDataLoadProvider3ImageVideoWrapperBitmapImageVideoDataLoadProvider4InputStreamGifDrawableGifDrawableLoadProvider5ImageVideoWrapperGifBitmapWrapperImageVideoGifDrawableLoadProvider6InputStreamFileStreamFileDataLoadProvider表1-3 ResourceType到TranscodeType的映射
IDDecodedClassTranscodedClassResourceTranscoder1BitmapGlideBitmapDrawableGlideBitmapDrawableTranscoder2GifBitmapWrapperGlideDrawableGifBitmapWrapperDrawableTranscoder上表 标题 提到的 ModelType、DataType、ResourceType和TranscodeType在GenericRequestBuilder类的注释中有说明:
/** * A generic class that can handle setting options and staring loads for generic resource types. * * @param <ModelType> The type of model representing the resource. * @param <DataType> The data type that the resource {@link com.bumptech.glide.load.model.ModelLoader} will provide that * can be decoded by the {@link com.bumptech.glide.load.ResourceDecoder}. * @param <ResourceType> The type of the resource that will be loaded. * @param <TranscodeType> The type of resource the decoded resource will be transcoded to. */ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> implements Cloneable { //省略代码部分 }对于这四种范型的理解是了解Glide运行的关键,接口LoadProvider范型A、T、Z、R与此对应。博主在这几个范型种绕了半天。大家只要参照着上面的三张表来看Glide源码,相信一定会有柳暗花明的感觉 :)
/** * An extension of {@link com.bumptech.glide.provider.DataLoadProvider} that also allows a * {@link com.bumptech.glide.load.model.ModelLoader} and a * {@link com.bumptech.glide.load.resource.transcode.ResourceTranscoder} to be retrieved. * * @param <A> The type of model. * @param <T> The type of data that will be decoded from. * @param <Z> The type of resource that will be decoded. * @param <R> The type of resource that the decoded resource will be transcoded to. */ public interface LoadProvider<A, T, Z, R> extends DataLoadProvider<T, Z> { //省略代码部分 }在步骤(一)中我们得到一个RequestManager对象,紧接着我们就来看看RequestManager对象的load(String)方法:
public DrawableTypeRequest<String> load(String string) { return (DrawableTypeRequest<String>) fromString().load(string); }从代码中我们得知,该方法返回了一个DrawableTypeRequest对象,有关DrawableTypeRequest实例的初始化过程,直接上图,大家参考着上面提供的三张表应该不难理解:
注意 理解了上图的朋友可以直接跳到下一小节,下面的描述很枯燥 :(
该对象的继承关系为DrawableTypeRequest–>DrawableRequestBuilder–>GenericRequestBuilder。这个对象用于加载load(String)参数所指代的内容。顺着load(String)方法,我们来重点看看fromString()–>loadGeneric(Class<T> modelClass)方法。由fromString()我们得知这里的modelClass即为String.class:
private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) { 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)); }很显然,上面方法中的泛型T即指代String。
在loadGeneric(Class<T> modelClass)方法中,我们来看第一行代码:
ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
由buildStreamModelLoader方法的注释我们得知,该方法是用来生成一个ModelLoader实例来用于提供InputStream输入源。
我们顺藤摸瓜,找到了GenericLoaderFactory类中的buildModelLoader(Class<T> modelClass, Class<Y> resourceClass)方法,该方法中的T与Y泛型在我们的调用过程中分别指代String和InputStream类型:
public synchronized <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass) { ModelLoader<T, Y> result = getCachedLoader(modelClass, resourceClass); if (result != null) { // We've already tried to create a model loader and can't with the currently registered set of factories, // but we can't use null to demonstrate that failure because model loaders that haven't been requested // yet will be null in the cache. To avoid this, we use a special signal model loader. if (NULL_MODEL_LOADER.equals(result)) { return null; } else { return result; } } final ModelLoaderFactory<T, Y> factory = getFactory(modelClass, resourceClass); if (factory != null) { result = factory.build(context, this); cacheModelLoader(modelClass, resourceClass, result); } else { // We can't generate a model loader for the given arguments with the currently registered set of factories. cacheNullLoader(modelClass, resourceClass); } return result; }在上述方法中,我们定位到这行代码:
final ModelLoaderFactory<T, Y> factory = getFactory(modelClass, resourceClass);
在这行代码中,我们是通过调用getFactory(Class<T> modelClass, Class<Y> resourceClass)方法来产生一个ModelLoaderFactory实例。现在我们就来看源码:
private <T, Y> ModelLoaderFactory<T, Y> getFactory(Class<T> modelClass, Class<Y> resourceClass) { Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> resourceToFactories = modelClassToResourceFactories.get(modelClass); ModelLoaderFactory/*T, Y*/ result = null; if (resourceToFactories != null) { result = resourceToFactories.get(resourceClass); } if (result == null) { for (Class<? super T> registeredModelClass : modelClassToResourceFactories.keySet()) { // This accounts for model subclasses, our map only works for exact matches. We should however still // match a subclass of a model with a factory for a super class of that model if if there isn't a // factory for that particular subclass. Uris are a great example of when this happens, most uris // are actually subclasses for Uri, but we'd generally rather load them all with the same factory rather // than trying to register for each subclass individually. if (registeredModelClass.isAssignableFrom(modelClass)) { Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> currentResourceToFactories = modelClassToResourceFactories.get(registeredModelClass); if (currentResourceToFactories != null) { result = currentResourceToFactories.get(resourceClass); if (result != null) { break; } } } } } return result; }很显然,我们是首先从Map表modelClassToResourceFactories中获取一个已注册的ModelLoaderFactory对象。那么,我们所需要的ModelLoaderFactory是否已经注册呢?翻看步骤(一)中提到的表1-1,是不是就是表中的ID 8 的内容?对应着条目8,我们获得了一个StreamStringLoader对象。后面获取引用fileDescriptorModelLoader的情况与此类似。
紧接着就生成了一个DrawableTypeRequest<String>对象,经过OptionsApplier对象进一步处理后返回到了之前RequestManager的fromString()方法。有关OptionsApplier对象的作用,我们在后文会提到。这里我们只需简单认为返回了一个原生态的DrawableTypeRequest<String>对象即可。
在创建DrawableTypeRequest对象时,我们要提到一个重要的类FixedLoadProvider(上文已经提及 :) )。这个类实例在后面请求网络图片时会用到。在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) { 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); }代码清单1-2
在这个方法中,我们重点留意下transcoder实例、DataLoadProvider类和ImageVideoModelLoader类。通过Glide的构造函数和表1-2、表1-3,我们很容易得到这里的transcoder实例为GifBitmapWrapperDrawableTranscoder对象(表1-3条目2),DataLoadProvider实例为类ImageVideoGifDrawableLoadProvider的对象(表1-2条目5),而这里的ImageVideoModelLoader就对应了表1-1中的条目(14*)。
有关ImageVideoGifDrawableLoadProvider的来龙去脉,直接看下图,后面数据流转图片的逻辑就靠它了:)
回到RequestManager的load(String string)方法,接下来即是调用DrawableTypeRequest<String>对象的load(String)方法了。这个方法很简单,只是保存了状态而已:
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) { this.model = model; isModelSet = true; return this; }现在我们来看看加载图片的最后一步into(fullscreenView)。在这里,fullscreenView是个ImageView实例。据此我们顺着方法的调用定位到了GenericRequestBuilder类的into(ImageView view)方法:
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)); }我们暂且忽略图片的变换逻辑,只看图片的加载过程。在步骤(二)中我们很容易确定,该方法中的TranscodeType指代GlideDrawable类,而transcodeClass即为GlideDrawable的一个实例(可参看图1-1)。代码glide.buildImageViewTarget(view, transcodeClass)返回了一个GlideDrawableImageViewTarget对象。这个类的作用后面在显示图片的时候会用到,这里暂且不表。下面我们来看方法into(Y 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"); } if (!isModelSet) { throw new IllegalArgumentException("You must first set a model (try #load())"); } Request previous = target.getRequest(); if (previous != null) { previous.clear(); requestTracker.removeRequest(previous); previous.recycle(); } Request request = buildRequest(target); target.setRequest(request); lifecycle.addListener(target); requestTracker.runRequest(request); return target; }代码清单1-3
这个方法我们需要重点关心的是Request类。这个类的具体子类即是根据图片路径来加载图片到ImageView中。现在我们就来看看这个Request的具体实例(buildRequest(Target<TranscodeType> target)--> buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator)):
private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) { 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); 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); return coordinator; } else { // Base case: no thumbnail. return obtainRequest(target, sizeMultiplier, priority, parentCoordinator); } }我们先忽略缩略图问题,直接到本方法的最后来看看GenericRequest.obtain()方法(obtainRequest()-->GenericRequest.obtain()):
private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority, RequestCoordinator requestCoordinator) { 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); }这个方法涉及到了很多实例对象,而这些实例对象中,我们首先需要关注的就是loadProvider和glide.getEngine()两个具体对象。这两个对象在上面两个步骤中已经涉及。后面我们将看到它们的具体作用。
获取到GenericRequest对象后,我们再次回到代码清单1-3的Y into(Y target)方法中。我们看到有这一行代码:
requestTracker.runRequest(request);
很显然,这一行代码便是要加载我们的图片了。按图索骥,我们来到了GenericRequest类的begin()方法。
在该方法中,我们要关注的是该类的onSizeReady(int width, int height)方法:
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; 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)); } }代码清单1-4
在onSizeReady方法中,我们再次看到了loadProvider的影子。在步骤(二)的最后我们提到了FixedLoadProvider对象,而这里的loadProvider其实就是FixedLoadProvider类的一个封装类ChildLoadProvider的实例。此时朋友们可能有疑问,在什么时候FixedLoadProvider对象就变成了ChildLoadProvider对象了呢?其实就是在步骤(二)中获取DrawableTypeRequest对象时进行了封装。在DrawableTypeRequest的祖父类GenericRequestBuilder的构造函数中:
this.loadProvider = loadProvider != null ? new ChildLoadProvider<ModelType, DataType, ResourceType, TranscodeType>(loadProvider) : null;
看到这里我们就明白了,在GenericRequest的onSizeReady方法中(见代码清单1-4),我们得到的modelLoader对象即为步骤(二)中提到的ImageVideoModelLoader类的实例。而这里的dataFetcher对象即为StringLoader类(StreamStringLoader的基类)的方法getResourceFetcher获取的DataFetcher实例:
@Override public DataFetcher<T> getResourceFetcher(String model, int width, int height) { Uri uri; if (TextUtils.isEmpty(model)) { return null; } else if (model.startsWith("/")) { uri = toFileUri(model); } else { uri = Uri.parse(model); final String scheme = uri.getScheme(); if (scheme == null) { uri = toFileUri(model); } } return uriLoader.getResourceFetcher(uri, width, height); }按照步骤(二)中获取StreamStringLoader的方式,并结合表1-1,我们一步步得到上述方法中的uriLoader实例即为HttpUrlGlideUrlLoader对象。下面我们就来看看类HttpUrlGlideUrlLoader的getResourceFetcher方法:
@Override public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) { // GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time spent parsing urls. GlideUrl url = model; if (modelCache != null) { url = modelCache.get(model, 0, 0); if (url == null) { modelCache.put(model, 0, 0, model); url = model; } } return new HttpUrlFetcher(url); }由于我们是初次调用Glide来加载图片,所以会生成一个HttpUrlFetcher对象。而这个对象即是代码清单1-4中方法onSizeReady的DataFetcher对象实例dataFetcher。
我们接着代码清单1-4往下看,有这么一行代码:
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder, priority, isMemoryCacheable, diskCacheStrategy, this);
这一行便是加载图片并显示的过程了。我们进到Engine的load方法中(这里的engine实例即为上述GenericRequest.obtain中传递过来的Engine对象,也就是在生成Glide对象时GlideBuilder创建的Engine实例):
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(); //这里省略了有关缓存方面的代码 .................. .................. 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); return new LoadStatus(cb, engineJob); }在这个方法中,我们主要关心的是EngineRunnable的run方法:
@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); } }代码清单1-5
进一步,我们来到decode()方法中:
private Resource<?> decode() throws Exception { if (isDecodingFromCache()) { return decodeFromCache(); } else { return decodeFromSource(); } }在EngineRunnable的构造方法中,stage默认赋值为Stage.CACHE,所以在decode方法中首先会调用decodeFromCache方法。很显然,由于我们是首次加载图片,缓存中是没有的。所以在代码清单1-5中,我们拿到的resource为null,此时onLoadFailed方法会被调起:
private void onLoadFailed(Exception e) { if (isDecodingFromCache()) { stage = Stage.SOURCE; manager.submitForSource(this); } else { manager.onException(e); } }在该方法中,stage被重置为Stage.SOURCE,并将EngineRunnable提交给了EngineRunnableManager对象。
从Engine的load方法中,我们很容易获得EngineRunnableManager的具体实例为EngineJob的对象:
public void submitForSource(EngineRunnable runnable) { future = sourceService.submit(runnable); }EngineJob的submitForSource方法很简单,只有一行代码,即将一个线程放入线程池中等待被调用。这样,待线程被调起时,我们又回到了代码清单1-5,此时根据isDecodingFromCache方法返回false而来到了decodeFromSource方法中:
private Resource<?> decodeFromSource() throws Exception { return decodeJob.decodeFromSource(); }进入到DecodeJob的decodeFromSource方法:
public Resource<Z> decodeFromSource() throws Exception { Resource<T> decoded = decodeSource(); return transformEncodeAndTranscode(decoded); }代码清单1-6
接着我们来查看decodeSource方法:
private Resource<T> decodeSource() throws Exception { Resource<T> decoded = null; try { long startTime = LogTime.getLogTime(); final A data = fetcher.loadData(priority); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Fetched data", startTime); } if (isCancelled) { return null; } decoded = decodeFromSourceData(data); } finally { fetcher.cleanup(); } return decoded; }看到这里,我们终算拿到了数据源:
final A data = fetcher.loadData(priority);
这里的fetcher即是我们上文提到的HttpUrlFetcher类的实例,那么现在我们就来看看它是如何加载数据源的:
@Override public InputStream loadData(Priority priority) throws Exception { return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders()); }顺着该方法走下去,我们便明白了,Glide默认加载网络图片是通过HttpURLConnection方式。
在这里,我们拿到的数据源是一个InputStream输入流。而我们的要看到的是一张张的图片。这又是如何获取的呢?
OK,顺着方法往下看,我们来到这行:
decoded = decodeFromSourceData(data);进入到decodeFromSourceData方法:
private Resource<T> decodeFromSourceData(A data) throws IOException { final Resource<T> decoded; if (diskCacheStrategy.cacheSource()) { decoded = cacheAndDecodeSourceData(data); } else { long startTime = LogTime.getLogTime(); decoded = loadProvider.getSourceDecoder().decode(data, width, height); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Decoded from source", startTime); } } return decoded; }同样避开缓存不谈,直接看下面这行:
decoded = loadProvider.getSourceDecoder().decode(data, width, height);追本溯源,这里的loadProvider还是那个ChildLoadProvider,而它的SourceDecoder即是步骤(二)中图1-2的ImageVideoGifDrawableLoadProvider的sourceDecoder,即类GifBitmapWrapperResourceDecoder的实例。
我们顺着GifBitmapWrapperResourceDecoder的decode方法走,我们来到这个方法:
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); 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); } return result; }在这个方法中,会根据ImageHeaderParser.ImageType来决定是解码为Gif图片还是Bitmap图片。这里我们就先来看看普通的Bitmap是如何解码的。而有关Gif图片的解码过程,有兴趣的朋友可以看看。后面的系列博客中我们再来一同研究交流。好了,直接上代码:
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) { result = new GifBitmapWrapper(bitmapResource, null); } return result; }结合着图1-2,我们定位到了ImageVideoBitmapDecoder的decode方法中。很显然,这也是个不干事儿的主儿,走在一线的是它的streamDecoder。这个成员变量在哪里初始化的呢?我们回到类ImageVideoDataLoadProvider中,在其构造方法中我们找到了一点线索:
sourceDecoder = new ImageVideoBitmapDecoder(streamBitmapProvider.getSourceDecoder(), fileDescriptorBitmapProvider.getSourceDecoder());好吧,我们又回到了Glide的构造函数中,参照着表1-2和图1-2来看,这里的sourceDecoder即是StreamBitmapDecoder。话不多说,我们来看看该类中是否有我们要找的decode方法吧:
@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); }哈哈,我们终于看到了Bitmap的身影。进入Downsampler中查看,好吧,这个我们留到后面再说。
拿到Bitmap后我们再次回到GifBitmapWrapperResourceDecoder的decodeBitmapWrapper方法中,很显然,这里对我们的Bitmap做了一次封装,返回了一个Resource<GifBitmapWrapper>对象。带着这个对象,我们回到代码清单1-6进入到DecodeJob的decodeFromSource方法中,查看transformEncodeAndTranscode方法的调用:
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<Z> result = transcode(transformed); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Transcoded transformed from source", startTime); } return result; }方法中我们主要是关注下面这行:
Resource<Z> result = transcode(transformed);这里transcode方法接受的参数transformed是GifBitmapWrapper转变后的GifBitmapWrapper对象。这里暂且不表。我们来看transcode方法:
private Resource<Z> transcode(Resource<T> transformed) { if (transformed == null) { return null; } return transcoder.transcode(transformed); }这里我们又迎来了一个“狠角色”transcoder。为了找到它的来源,我们又回到了创建FixedLoadProvider实例的地方代码清单1-2中。这里用到的transcoder便是那里获得到的GifBitmapWrapperDrawableTranscoder类的实例。我们来看看它的transcode方法:
public Resource<GlideDrawable> transcode(Resource<GifBitmapWrapper> toTranscode) { GifBitmapWrapper gifBitmap = toTranscode.get(); Resource<Bitmap> bitmapResource = gifBitmap.getBitmapResource(); final Resource<? extends GlideDrawable> result; if (bitmapResource != null) { 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; }从前面我们已经知道,此处的bitmapResource不为null,所以会执行
bitmapDrawableResourceTranscoder.transcode(bitmapResource);这里的bitmapDrawableResourceTranscoder就是哪个呢?呵呵,我们再次来到Glide的构造方法中,在方法最后几行,我们找到了线索:
transcoderRegistry.register(Bitmap.class, GlideBitmapDrawable.class, new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool)); transcoderRegistry.register(GifBitmapWrapper.class, GlideDrawable.class, new GifBitmapWrapperDrawableTranscoder( new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool)));没错,这里的bitmapDrawableResourceTranscoder便是类GlideBitmapDrawableTranscoder的实例。我们来一起看看它的transcode方法:
@Override public Resource<GlideBitmapDrawable> transcode(Resource<Bitmap> toTranscode) { GlideBitmapDrawable drawable = new GlideBitmapDrawable(resources, toTranscode.get()); return new GlideBitmapDrawableResource(drawable, bitmapPool); }OK,这里我们拿到一个包装类GlideBitmapDrawableResource。
在拿到GlideBitmapDrawableResource后,我们再回到EngineRunnable的run方法中(见代码清单1-5)。有了数据源会调用EngineRunnable的onLoadComplete(Resource resource)方法:
private void onLoadComplete(Resource resource) { manager.onResourceReady(resource); }沿着方法的调用顺序,我们回到了GenericRequest的onResourceReady方法:
public void onResourceReady(Resource<?> resource) { //省略无关代码 .............. .............. Object received = resource.get(); //省略无关代码 .............. .............. onResourceReady(resource, (R) received); }这个回调方法中回传的不再是我们前面获取到的GlideBitmapDrawableResource对象,而是被包装后的EngineResource对象。不过这对我们理解Glide的图片加载流程没有任何的影响,依然可以认为是GlideBitmapDrawableResource的对象。received是从GlideBitmapDrawableResource中获取到的GlideBitmapDrawable。 接着往下看:
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); } }在该方法中,我们关注这么两行代码:
GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource); target.onResourceReady(result, animation);这里的target对象就是本小节一开始提到的GlideDrawableImageViewTarget的实例。现在我们就来看看它的onResourceReady方法:
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) { //省略无关代码 ................. ................. super.onResourceReady(resource, animation); //省略无关代码 ................. ................. }找到它的基类,我们会发现最终又回到了它的setResource方法:
@Override protected void setResource(GlideDrawable resource) { view.setImageDrawable(resource); }到这里,我们Glide加载图片的主要流程就结束了。其中涉及到的图片转换、缓存、动画等问题我会在此系列博客中有所涉及,这里先暂且不提。
经过上面的三步骤,一张网络图片就加载到了我们的View上。当然,这其中涉及到的内容还有很多,我这里只是帮大家梳理下Glide加载图片的主要流程。现在再回头对照着步骤(一)中的三张表,相信大家对ModelType、DataType、ResourceType和TranscodeType会有更深的理解。从上面的分析中我们也看到了,理解了这四种范型对应的类的功能,也便理解了Glide的主要概念和功能。
后面的文章中我们会重点来查看Glide的缓存过程,请大家多多指点多多交流。
相关资源:一行代码利用Glide加载网络图片并显示