前言 在众多的图片加载框架中,Glide 是 Google 推荐的,并在自家的项目中大量使用的一个非常强大的框架,专注于平滑滚动,并且还提供 Gif,本地 Vedio 首帧的解码和显示。Glide 提供了非常便捷的链式调用接口,以及丰富的拓展和自定义功能,开发者可以非常简单地对框架进行配置和图片再加工。
如今 Gilde 已经更新到4.x,了解其源码对更好的使用 Glide ,以及学习相关的图片处理技术,学习更优雅的编码会有很大的帮助。
不得不说,Glide 整个框架的极其复杂的,特别是在对资源的转换和解码过程中,涉及了许多的嵌套循环,同时也使用了大量的工厂模式用于生产转换模块,编码模块,解码模块等,笔者在阅读过程中,多次迷失在茫茫的代码流中。
为此,萌生了将对 Glide 的理解记录成文的想法,借以理清思路。
那么接下来,我们就先看看 Glide 是如何进行框架初始化的。
探究 Glide.with发生了什么? 1. Glide单例的加载 使用过 Glide 的都知道,调用 Glide 加载一张图片时,第一句代码便是 Glide.with(this),这里肯定就是 Glide 的入口了,通过这句代码,Glide 开始了“漫漫的”初始化之路。
Glide 重载了多个 with 的方法,分别用于不同的情境下使用,我们看其中最常用的在 Activity 中调用的方法,即
1 2 3 4 @NonNull public static RequestManager with (@NonNull Activity activity) { return getRetriever(activity).get(activity); }
首先,跟进 getRetriever(activity)
1 2 3 4 5 6 7 8 9 10 11 @NonNull private static RequestManagerRetriever getRetriever (@Nullable Context context) { Preconditions.checkNotNull( context, "You cannot start a load on a not yet attached View or a Fragment where getActivity() " + "returns null (which usually occurs when getActivity() is called before the Fragment " + "is attached or after the Fragment is destroyed)." ); return Glide.get(context).getRequestManagerRetriever(); }
这里首先检查了 context 是否为空,如果为 null,抛出异常。
我们重点来看 Glide.get(context)
1 2 3 4 5 6 7 8 9 10 11 12 @NonNull public static Glide get (@NonNull Context context) { if (glide == null ) { synchronized (Glide.class) { if (glide == null ) { checkAndInitializeGlide(context); } } } return glide; }
这里是一个典型的双检锁单例模式。
继续跟进 checkAndInitialzeGlide(context)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private static void checkAndInitializeGlide (@NonNull Context context) { if (isInitializing) { throw new IllegalStateException("You cannot call Glide.get() in registerComponents()," + " use the provided Glide instance instead" ); } isInitializing = true ; initializeGlide(context); isInitializing = false ; } private static void initializeGlide (@NonNull Context context) { initializeGlide(context, new GlideBuilder()); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 @SuppressWarnings ("deprecation" )private static void initializeGlide (@NonNull Context context, @NonNull GlideBuilder builder) { Context applicationContext = context.getApplicationContext(); GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules(); List<com.bumptech.glide.module .GlideModule> manifestModules = Collections.emptyList(); if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) { manifestModules = new ManifestParser(applicationContext).parse(); } if (annotationGeneratedModule != null && !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) { Set<Class<?>> excludedModuleClasses = annotationGeneratedModule.getExcludedModuleClasses(); Iterator<com.bumptech.glide.module .GlideModule> iterator = manifestModules.iterator(); while (iterator.hasNext()) { com.bumptech.glide.module .GlideModule current = iterator.next(); if (!excludedModuleClasses.contains(current.getClass())) { continue ; } iterator.remove(); } } if (Log.isLoggable(TAG, Log.DEBUG)) { for (com.bumptech.glide.module .GlideModule glideModule : manifestModules) { Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass()); } } RequestManagerRetriever.RequestManagerFactory factory = annotationGeneratedModule != null ? annotationGeneratedModule.getRequestManagerFactory() : null ; builder.setRequestManagerFactory(factory); for (com.bumptech.glide.module .GlideModule module : manifestModules) { module .applyOptions(applicationContext, builder); } if (annotationGeneratedModule != null ) { annotationGeneratedModule.applyOptions(applicationContext, builder); } Glide glide = builder.build(applicationContext); for (com.bumptech.glide.module .GlideModule module : manifestModules) { module .registerComponents(applicationContext, glide, glide.registry); } if (annotationGeneratedModule != null ) { annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry); } applicationContext.registerComponentCallbacks(glide); Glide.glide = glide; }
留意最后将初始化得到的glide赋值给了Glide.glide的单例。
接下里就来看看在这初始化方法中,Glide都加载了哪些配置。
2. GlideModule配置加载 在使用 Glide 的时候,我们都会有一些想要设置的系统级配置,如设置缓存的存储位置,缓存区的大小,网络加载模块等等,那么我们通常就是使用 GldieModule
进行配置。在 Glide3.x 中,我们首先会定义一个继承于 GlideModule
的类,然后在项目的 AndroidMenifest.xml
中进行指定:
1 2 <meta-data android:name ="com.test.GlideConfiguration" android:value ="GlideModule" />
而在 Glide4 中,提供另外一个配置的模式,那就是注解,并且不再继承 GlideModule ,而是继承 AppGlideModule 和 LibraryGlideModule,分别对应 Application 和 Library,使用 @GlideModule 注解进行标记。而 Glide3.x 中的配置方式已经建议放弃使用。示例如下:
1 2 3 4 5 6 7 8 @GlideModule public class GlideConfiguration extends AppGlideModule { @Override public void applyOptions (Context context, GlideBuilder builder) { builder.setDiskCache(new ExternalPreferredCacheDiskCacheFactory(context)); } }
Glide 是如何对 GlideModule 的配置进行初始化的呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Context applicationContext = context.getApplicationContext(); GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules(); List<com.bumptech.glide.module .GlideModule> manifestModules = Collections.emptyList(); if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) { manifestModules = new ManifestParser(applicationContext).parse(); } if (annotationGeneratedModule != null && !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) { Set<Class<?>> excludedModuleClasses = annotationGeneratedModule.getExcludedModuleClasses(); Iterator<com.bumptech.glide.module .GlideModule> iterator = manifestModules.iterator(); while (iterator.hasNext()) { com.bumptech.glide.module .GlideModule current = iterator.next(); if (!excludedModuleClasses.contains(current.getClass())) { continue ; } iterator.remove(); } }
第二行代码中,getAnnotationGeneratedGlideModules()
会获取 Glide 注解自动生产的一个 Glide 的 Module 配置器。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Nullable @SuppressWarnings ({"unchecked" , "deprecation" , "TryWithIdenticalCatches" })private static GeneratedAppGlideModule getAnnotationGeneratedGlideModules () { GeneratedAppGlideModule result = null ; try { Class<GeneratedAppGlideModule> clazz = (Class<GeneratedAppGlideModule>) Class.forName("com.bumptech.glide.GeneratedAppGlideModuleImpl" ); result = clazz.getDeclaredConstructor().newInstance(); } catch (ClassNotFoundException e) { if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Failed to find GeneratedAppGlideModule. You should include an" + " annotationProcessor compile dependency on com.github.bumptech.glide:compiler" + " in your application and a @GlideModule annotated AppGlideModule implementation or" + " LibraryGlideModules will be silently ignored" ); } } catch (InstantiationException e) { throwIncorrectGlideModule(e); } catch (IllegalAccessException e) { throwIncorrectGlideModule(e); } catch (NoSuchMethodException e) { throwIncorrectGlideModule(e); } catch (InvocationTargetException e) { throwIncorrectGlideModule(e); } return result; }
其中 com.bumptech.glide.GeneratedAppGlideModuleImpl
是在编译时由 Glide 生成的一个类,主要用于过滤不必要的 GlideModule ,以及提供一个请求检索器工厂,这个后面会讲到。
接下生成一个 Manifest 解析器 ManifestParser ,用于获取配置的 GlideModule ,并存放在 manifestModules 中。然后是一个判断
1 2 3 4 if (annotationGeneratedModule != null && !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) { ...... }
如果条件成立,即编译时自动生成的类中,包含了需要排除的 GlideModule ,逐个将其移除。
接着以上代码,Glide 将逐个调用剩下的 GlideModule ,并回调 applyOptions
和 registerComponents
接口,这时,用户配置的 GlideModule 就会被调用,同时用户设置的参数也就被配置到 Glide 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 RequestManagerRetriever.RequestManagerFactory factory = annotationGeneratedModule != null ? annotationGeneratedModule.getRequestManagerFactory() : null ; builder.setRequestManagerFactory(factory); for (com.bumptech.glide.module .GlideModule module : manifestModules) { module .applyOptions(applicationContext, builder); } if (annotationGeneratedModule != null ) { annotationGeneratedModule.applyOptions(applicationContext, builder); } Glide glide = builder.build(applicationContext); for (com.bumptech.glide.module .GlideModule module : manifestModules) { module .registerComponents(applicationContext, glide, glide.registry); } if (annotationGeneratedModule != null ) { annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry); } applicationContext.registerComponentCallbacks(glide); Glide.glide = glide;
在以上代码中,发现一句代码,在回调 registerComponents
前,首先构建了 glide 的实例。
1 Glide glide = builder.build(applicationContext);
3. GlideBuilder构建Glide单例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 @NonNull Glide build (@NonNull Context context) { if (sourceExecutor == null ) { sourceExecutor = GlideExecutor.newSourceExecutor(); } if (diskCacheExecutor == null ) { diskCacheExecutor = GlideExecutor.newDiskCacheExecutor(); } if (animationExecutor == null ) { animationExecutor = GlideExecutor.newAnimationExecutor(); } if (memorySizeCalculator == null ) { memorySizeCalculator = new MemorySizeCalculator.Builder(context).build(); } if (connectivityMonitorFactory == null ) { connectivityMonitorFactory = new DefaultConnectivityMonitorFactory(); } if (bitmapPool == null ) { int size = memorySizeCalculator.getBitmapPoolSize(); if (size > 0 ) { bitmapPool = new LruBitmapPool(size); } else { bitmapPool = new BitmapPoolAdapter(); } } if (arrayPool == null ) { arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes()); } if (memoryCache == null ) { memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize()); } if (diskCacheFactory == null ) { diskCacheFactory = new InternalCacheDiskCacheFactory(context); } if (engine == null ) { engine = new Engine( memoryCache, diskCacheFactory, diskCacheExecutor, sourceExecutor, GlideExecutor.newUnlimitedSourceExecutor(), GlideExecutor.newAnimationExecutor(), isActiveResourceRetentionAllowed); } RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(requestManagerFactory); return new Glide( context, engine, memoryCache, bitmapPool, arrayPool, requestManagerRetriever, connectivityMonitorFactory, logLevel, defaultRequestOptions.lock(), defaultTransitionOptions); }
通过以上一系列工具的新建,Glide 建立了资源请求线程池,本地缓存加载线程池,动画线程池,内存缓存器,磁盘缓存工具等等,接着构造了 Engine 数据加载引擎,最后再将 Engine 注入 Glide ,构建 Glide 。
其中还建立了一个请求器索引器,用于索引 RequestManger ,后面我们再详细讲。
我们进入最后, 构建 Glide 。
4. 构建Glide,配置数据转换器/解码器/转码器/编码器 回到 Glide 中,看看 Glide 的构造函数,这是一个长得变态的构造函数(有200行),但是不必被它吓倒(好吧,其实第一次看到这里,我是被吓倒了,直接略过去了,限于文章篇幅,这里只截取了部分源码,仔细的话可以直接看源码),仔细分析一下,其实整个构造过程并没那么复杂。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 Glide( @NonNull Context context, @NonNull Engine engine, @NonNull MemoryCache memoryCache, @NonNull BitmapPool bitmapPool, @NonNull ArrayPool arrayPool, @NonNull RequestManagerRetriever requestManagerRetriever, @NonNull ConnectivityMonitorFactory connectivityMonitorFactory, int logLevel, @NonNull RequestOptions defaultRequestOptions, @NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions) { this .engine = engine; this .bitmapPool = bitmapPool; this .arrayPool = arrayPool; this .memoryCache = memoryCache; this .requestManagerRetriever = requestManagerRetriever; this .connectivityMonitorFactory = connectivityMonitorFactory; DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT); bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat); final Resources resources = context.getResources(); registry = new Registry(); registry.register(new DefaultImageHeaderParser()); Downsampler downsampler = new Downsampler(registry.getImageHeaderParsers(), resources.getDisplayMetrics(), bitmapPool, arrayPool); ByteBufferGifDecoder byteBufferGifDecoder = new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), bitmapPool, arrayPool); ResourceDecoder<ParcelFileDescriptor, Bitmap> parcelFileDescriptorVideoDecoder = VideoDecoder.parcel(bitmapPool); ByteBufferBitmapDecoder byteBufferBitmapDecoder = new ByteBufferBitmapDecoder(downsampler); StreamBitmapDecoder streamBitmapDecoder = new StreamBitmapDecoder(downsampler, arrayPool); ResourceDrawableDecoder resourceDrawableDecoder = new ResourceDrawableDecoder(context); ResourceLoader.StreamFactory resourceLoaderStreamFactory = new ResourceLoader.StreamFactory(resources); ResourceLoader.UriFactory resourceLoaderUriFactory = new ResourceLoader.UriFactory(resources); ResourceLoader.FileDescriptorFactory resourceLoaderFileDescriptorFactory = new ResourceLoader.FileDescriptorFactory(resources); ResourceLoader.AssetFileDescriptorFactory resourceLoaderAssetFileDescriptorFactory = new ResourceLoader.AssetFileDescriptorFactory(resources); BitmapEncoder bitmapEncoder = new BitmapEncoder(arrayPool); BitmapBytesTranscoder bitmapBytesTranscoder = new BitmapBytesTranscoder(); GifDrawableBytesTranscoder gifDrawableBytesTranscoder = new GifDrawableBytesTranscoder(); ContentResolver contentResolver = context.getContentResolver(); registry .append(ByteBuffer.class, new ByteBufferEncoder()) .append(InputStream.class, new StreamEncoder(arrayPool)) .append(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder) .append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder) .append( Registry.BUCKET_BITMAP_DRAWABLE, ByteBuffer.class, BitmapDrawable.class, new BitmapDrawableDecoder<>(resources, byteBufferBitmapDecoder)) .append( Registry.BUCKET_GIF, InputStream.class, GifDrawable.class, new StreamGifDecoder(registry.getImageHeaderParsers(), byteBufferGifDecoder, arrayPool)) .append(Registry.BUCKET_GIF, ByteBuffer.class, GifDrawable.class, byteBufferGifDecoder) .append(GifDrawable.class, new GifDrawableEncoder()) .append( GifDecoder.class, GifDecoder.class, UnitModelLoader.Factory.<GifDecoder>getInstance()) .append( Registry.BUCKET_BITMAP, GifDecoder.class, Bitmap.class, new GifFrameResourceDecoder(bitmapPool)) .append(Uri.class, Drawable.class, resourceDrawableDecoder) .append( Uri.class, Bitmap.class, new ResourceBitmapDecoder(resourceDrawableDecoder, bitmapPool)) .register(new ByteBufferRewinder.Factory()) .append(File.class, ByteBuffer.class, new ByteBufferFileLoader.Factory()) .append(File.class, File.class, UnitModelLoader.Factory.<File>getInstance()) .register(new InputStreamRewinder.Factory(arrayPool)) .append(int .class, InputStream.class, resourceLoaderStreamFactory) .register( Bitmap.class, BitmapDrawable.class, new BitmapDrawableTranscoder(resources)) .register(Bitmap.class, byte [].class, bitmapBytesTranscoder); ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory(); glideContext = new GlideContext( context, arrayPool, registry, imageViewTargetFactory, defaultRequestOptions, defaultTransitionOptions, engine, logLevel); }
其中最重要的是步骤3和步骤4,分别为 Glide 初始化了模型转换加载器,解码器,转码器,编码器,并将对各种类型进行一一注册,将其列成表格如下:
转换器
功能
ResourceLoader.StreamFactory
将Android资源ID转换为Uri,在加载成为InputStream
ResourceLoader.UriFactory
将资源ID转换为Uri
ResourceLoader.FileDescriptorFactory
将资源ID转化为ParcelFileDescriptor
ResourceLoader.AssetFileDescriptorFactory
将资源ID转化为AssetFileDescriptor
UnitModelLoader.Factory
不做任何转换,返回源数据
ByteBufferFileLoader.Factory
将File转换为ByteBuffer
FileLoader.StreamFactory
将File转换为InputStream
FileLoader.FileDescriptorFactory
将File转化为ParcelFileDescriptor
DataUrlLoader.StreamFactory
将Url转化为InputStream
…
…
解码器
功能
ByteBufferGifDecoder
将ByteBuffer解码为GifDrawable
ByteBufferBitmapDecoder
将ByteBuffer解码为Bitmap
ResourceDrawableDecoder
将资源Uri解码为Drawable
ResourceBitmapDecoder
将资源ID解码为Bitmap
BitmapDrawableDecoder
将数据解码为BitmapDrawable
StreamBitmapDecoder
将InputStreams解码为Bitmap
StreamGifDecoder
将InputStream数据转换为BtyeBuffer,再解码为GifDrawable
GifFrameResourceDecoder
解码gif帧
FileDecoder
包装File成为FileResource
…
…
转码器
功能
BitmapDrawableTranscoder
将Bitmap转码为BitmapDrawable
BitmapBytesTranscoder
将Bitmap转码为Byte arrays
DrawableBytesTranscoder
将BitmapDrawable转码为Byte arrays
GifDrawableBytesTranscoder
将GifDrawable转码为Byte arrays
编码器
功能
ByteBufferEncoder
将Byte数据缓存为File
StreamEncoder
InputStream缓存为File
BitmapEncoder
将Bitmap数据缓存为File
BitmapDrawableEncoder
将BitmapDrawable数据缓存为File
GifDrawableEncoder
将GifDrawable数据缓存为File
源数据
转换数据
转换器
Integer.class
InputStream.class
ResourceLoader.StreamFactory
String.class
InputStream.class
DataUrlLoader.StreamFactory
Uri.class
InputStream.class
DataUrlLoader.StreamFactory
…
…
…
以上模型转换注册表非常重要,在Glide进入解码流程时,将会遍历这里注册的所有可能转换的情形,尝试进行数据转换。
这里只列出部分情形,其它还包括 File/Bitmap/Drawable/Byte 等等几乎涵括了日常使用的情况。
Glide的加载流程可以概括为以下流程:
model(数据源)-->data(转换数据)-->decode(解码)-->transformed(缩放)-->transcoded(转码)-->encoded(编码保存到本地)
其中,transformed 为对解码得到的图片数据进行缩放,如 FitCenter、CropCenter 等。
到这里,Glide 单例就构建完成了,让我们返回到 Glide#with 中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @NonNull public static RequestManager with (@NonNull FragmentActivity activity) { return getRetriever(activity).get(activity); } @NonNull private static RequestManagerRetriever getRetriever (@Nullable Context context) { Preconditions.checkNotNull( context, "You cannot start a load on a not yet attached View or a Fragment where getActivity() " + "returns null (which usually occurs when getActivity() is called before the Fragment " + "is attached or after the Fragment is destroyed)." ); return Glide.get(context).getRequestManagerRetriever(); }
在构建好 Glide 后,通过 getRequestManagerRetriever()
将会得到一个 RequestManagerRetriever ,即 RequestManager 的检索器,RequestManagerRetriever#get() 将为每个请求页面创建一个 RequestManager。
还记得 GlideBuilder#build 提到的一句代码吗?1 2 RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(requestManagerFactory);
没错,这里获取的就是它。这里就必须要讲到 Glide 数据请求的生命周期了。
我们都知道 Glide 会根据页面的生命周期来自动的开启和结束数据的请求,那么 Glide 是怎么做到的呢?
5. 生命周期管理 我们进入 RequestManagerRetriever#get(Activity) 方法中。
1 2 3 4 5 6 7 8 9 10 11 12 @SuppressWarnings ("deprecation" )@NonNull public RequestManager get (@NonNull Activity activity) { if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); android.app.FragmentManager fm = activity.getFragmentManager(); return fragmentGet( activity, fm, null , isActivityVisible(activity)); } }
首先,判断是否为后台线程,如果是,则使用 ApplicationContext 重新获取。 重点来看 else 代码块。先断言请求的页面是否已经销毁。否则获取当前页面的 FragmentManager,并传给 fragmentGet 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @SuppressWarnings ({"deprecation" , "DeprecatedIsStillUsed" })@Deprecated @NonNull private RequestManager fragmentGet (@NonNull Context context, @NonNull android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) { RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible); RequestManager requestManager = current.getRequestManager(); if (requestManager == null ) { Glide glide = Glide.get(context); requestManager = factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context); current.setRequestManager(requestManager); } return requestManager; } @NonNull SupportRequestManagerFragment getSupportRequestManagerFragment (FragmentActivity activity) { return getSupportRequestManagerFragment( activity.getSupportFragmentManager(), null , isActivityVisible(activity)); }
在 fragmentGet 中首先通过 getRequestManagerFragment() 来获取一个命名为 FRAGMENT_TAG 的 fragment,如不存在,则新建一个 RequestManagerFragment,并添加到当前页面中。
这里我们就可以猜到了,Glide 是通过在页面中添加一个 Fragment 来动态监听页面的创建和销毁,从而达到依赖页面生命周期,动态管理请求的目的。
在 RequestManagerFragment 构造函数中,注入了一个生命周期监听器 ActivityFragmentLifecycle,并在 Fragment 各个生命周期回调中,调用了对应的方法。
而 ActivityFragmentLifecycle 也紧接着会调用 lifecycleListener 监听器,而这个监听器其实就是 RequestManger。如下:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class ActivityFragmentLifecycle implements Lifecycle { private final Set<LifecycleListener> lifecycleListeners = Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>()); private boolean isStarted; private boolean isDestroyed; @Override public void addListener (@NonNull LifecycleListener listener) { lifecycleListeners.add(listener); if (isDestroyed) { listener.onDestroy(); } else if (isStarted) { listener.onStart(); } else { listener.onStop(); } } @Override public void removeListener (@NonNull LifecycleListener listener) { lifecycleListeners.remove(listener); } void onStart () { isStarted = true ; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onStart(); } } void onStop () { isStarted = false ; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onStop(); } } void onDestroy () { isDestroyed = true ; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onDestroy(); } } }
最后,RequestManagerRetriever#fragmentGet,判断这个Fragment的RequestManager是否存在,否则创建一个RequestManager,并将生命周期注入,同时RquestManager构建时,将会通过addListener注入生命周期回调(具体可以查看RequestManger构造函数)。
最后,Glide#with终将得到一个RequestManager。
至此,Glide的加载过程就解析完毕了。总结一下整个流程:
通过AndroidManifest和@GlideModule注解获取用户自定义配置GlideModule,并调用其对应的方法
通过GlideBuilder构建Glide:
新建线程池
新建图片缓存池和缓存池
新建内存缓存管理器
新建默认本地缓存管理器
新建请求引擎Engine
新建RequestManger检索器
新建Glide
Glide构造方法中,新建模型转换器,解码器,转码器,编码器,以及生成Glide上下文GlideContext
通过RequestManager检索器,建立生命周期监听,并建立一个RequestManager
Glide与GlideApp 如果在项目中已经使用了 Glide3.x ,并且想要升级到 Glide4.x ,那么你会发现,原来使用链式调用进行参数配置的方法已经被修改了,同一个封装到了 RequesOptions 中,如下:1 2 3 4 5 6 7 8 9 10 RequestOptions options = new RequestOptions() .centerCrop() .placeholder(R.mipmap.ic_launcher_round) .error(R.mipmap.ic_launcher) .priority(Priority.HIGH) .diskCacheStrategy(DiskCacheStrategy.NONE); Glide.with(this ) .load(ImageConfig.URL_GIF) .apply(options) .into(iv);
这样的话升级后将导致大量的修改,当然你也可以自己封装一下,但是 Glide 已经为我们做好了兼容方案。
还记得初始化是通过 @GlideModule 注解来注册自定义配置吗?只要在项目中定义这么一个配置,那么 Glide 将会自动帮我们生成一个 GlideApp 模块,封装了 Glide3.x 中的调用方式。
1 2 3 4 5 6 public class GlideConfiguration extends AppGlideModule { @Override public void applyOptions (Context context, GlideBuilder builder) { } }
调用如下,还是原来的配方,还是熟悉的味道~
1 2 3 4 5 6 7 GlideApp.with(this ) .load(ImageConfig.URL_WEBP) .sizeMultiplier(0.5f ) .centerCrop() .diskCacheStrategy(DiskCacheStrategy.ALL) .error(R.mipmap.ic_launcher) .into(iv);
如果你还觉得不爽,那么你甚至可以把GlideApp直接修改为Glide,实现几乎“无缝对接”。当然,你还是要修改引用路径的。
1 2 3 4 5 6 7 @GlideModule (glideName="Glide" )public class GlideConfiguration extends AppGlideModule { @Override public void applyOptions (Context context, GlideBuilder builder) { } }
来源: