三思系列:Glide 4.X全方位认知 -- 模块职责概览 | Glide(一)
最近在解决一些问题时,进行了一下检索,发现 绝大多数文章
是 基于3.X
。Glide从进入4.X也有两三年了,在3.X的基础上,发生了很多变化。 所幸我对 4.X
的源码还比较熟,且Glide的设计也很精彩,索性写一写 对4.X的剖析
。
当然,对于多数读者而言,因为有一定的基础知识,这些剖析文章并不是满地金砖了,可以泛读查漏。
三思系列是我最新的学习、总结形式,着重于:问题分析、技术积累、视野拓展,了解更多
本文主旨
Glide是一个 庞大
的项目,这一篇旨在对Glide项目4.X版本进行 全方位的认知
具体为:了解Glide处理哪些问题,哪些模块与之相对应
对早年间 Square公司开源的 Picasso
比较熟悉的读者而言,不难理解:Picasso
是一个 小而雅
的框架,聚焦于图片加载的以下4点主要问题:
异步过程管理与调度
资源与显示容器多对多关系
多级缓存
图片转换支持ScaleType
而后起之秀 Glide
已经是一个 博大且细致
的图片异步加载框架。
在Glide 1.X 时期,两者的关注点基本一致,随着官方支持Glide的发展,它的关注点也越来越多,包括但不限于:
资源的封装
资源获取方式与过程
缓存
decode
、encode
的过程Target的抽象
,注:媒体资源获取的最终目标,例如存为文件、加载到ImageView中等图片转换
资源与Target多对多关系
生命周期感知与控制
仔细思考这些点之后,我们不难发现,Glide已经着眼于解决这样一个问题:
构建一个系统,对指定的标识媒体资源的实体,其封装形式可以自行扩展,执行资源的获取,并应用内存、磁盘进行缓存,封装图片的解码过程,按指定要求进行 裁切、缩放等图片转换,最终将结果运用到指定的目标。并对整个过程按照Android平台特性进行生命周期管理。
而这个过程中的绝大多数 节点
或者称之为 切面
,均可进行 外部扩展
这一点我们可以从项目介绍中得到印证:看重点单词即可
Glide is a fast and efficient open source
media management
andimage loading framework
for Android that wrapsmedia decoding
,memory and disk caching
, andresource pooling
into a simple and easy to use interface.Glide supports
fetching
,decoding
, anddisplaying
video stills, images, and animated GIFs. Glide includes a flexible API that allows developers to plug in to almost any network stack. By default Glide uses a customHttpUrlConnection
based stack, but also includes utility libraries plug in to Google's Volley project or Square's OkHttp library instead.Glide's
primary focus
is onmaking scrolling any kind of a list of images
assmooth and fast
as possible, but Glide is also effective foralmost any case
where you need tofetch
,resize
, anddisplay
a remote image.
模块职责划分,从Glide的构建过程窥一斑
不难理解:一个庞大的系统需要在符合 SRP
的基础上进行职责划分,这样一来,类就会变得很多,构建过程会变得复杂,利用Builder模式可以很好的解决这一问题。
class GlideBuilder {
public 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);
}
}
从这里我们可以收集到一下有效信息
- 缓存与池
- MemorySizeCalculator
- LruBitmapPool
- BitmapPoolAdapter
- LruArrayPool
- LruResourceCache
- InternalCacheDiskCacheFactory
- 资源获取
- RequestManagerRetriever
- DefaultConnectivityMonitorFactory
- 核心流程管理
- Engine
- 线程池
- GlideExecutor
再看到构造函数:代码挺长,略去了部分内容
class Glide {
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())
/*略去一段内容,太长了*/
.register(GifDrawable.class, byte[].class, gifDrawableBytesTranscoder);
ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
glideContext =
new GlideContext(
context,
arrayPool,
registry,
imageViewTargetFactory,
defaultRequestOptions,
defaultTransitionOptions,
engine,
logLevel);
}
}
这一段可以分为即可部分:
- builder 的 field 对应取值赋值
- 构建非开放的
BitmapPreFiller
实例 - 构建
Registry
实例registry
- 构建
DefaultImageHeaderParser
、ResourceLoader
、Decoder
、ResourceTranscoder
并将之注册到registry
- 构建
GlideContext
实例glideContext
按照经验推断,Registry 是一个策略注册表,服务于 策略模式
。
不难理解:Glide的工作环境非常复杂,例如获取资源,其资源存在位置可能在网络中的某个位置、 可能在应用的Assets中,也可能在其他位置,对于某一个目标,根据场景不同,存在不同的实现策略
继续按照经验推断,注册会分为不同的策略组,对应不同的目标,这一点我们稍后再看。
再按照我们常见的使用习惯,追踪一下初始化过程:泛读即可
class Glide {
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
return glide;
}
private static void checkAndInitializeGlide(@NonNull Context context) {
//...
initializeGlide(context);
//...
}
//重载略去
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// Context could be null for other reasons (ie the user passes in null), but in practice it will
// only occur due to errors with the Fragment lifecycle.
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.with(...)
开始得到 RequestManager
,当然,也可以以 Glide.get(context).getRequestManagerRetriever()
方式获取。如果Glide没有初始化,则会调用 initializeGlide
进行初始化。
跟进一下代码,泛读即可
class Glide {
private static void initializeGlide(@NonNull Context context) {
initializeGlide(context, new GlideBuilder());
}
@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;
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
}
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;
}
}
泛读之后,我们发现主要有 三步
:
- 构建GlideBuilder
- 通过反射,加载
可能存在
的自定义模块,设置到Builder中 - 构建Glide
思危:如果直接使用GlideBuilder进行构建,则无法直接运用自定义模块的内容,需要自行注入。
模块职责划分,于Register挖细节
上一节中,我们略去了Glide实例化过程的一些细节,其实现内容为:向Register注册了各种模块,可以泛读一下源码:
registry
.append(ByteBuffer.class,new ByteBufferEncoder())
.append(InputStream.class,new StreamEncoder(arrayPool))
/* Bitmaps */
.append(Registry.BUCKET_BITMAP,ByteBuffer.class,Bitmap.class,byteBufferBitmapDecoder)
.append(Registry.BUCKET_BITMAP,InputStream.class,Bitmap.class,streamBitmapDecoder)
.append(
Registry.BUCKET_BITMAP,
ParcelFileDescriptor.class,
Bitmap.class,
parcelFileDescriptorVideoDecoder)
.append(
Registry.BUCKET_BITMAP,
AssetFileDescriptor.class,
Bitmap.class,
VideoDecoder.asset(bitmapPool))
.append(Bitmap.class,Bitmap.class,UnitModelLoader.Factory.<Bitmap>getInstance())
.append(
Registry.BUCKET_BITMAP,Bitmap.class,Bitmap.class,new UnitBitmapDecoder())
.append(Bitmap.class,bitmapEncoder)
/* BitmapDrawables */
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
ByteBuffer.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources,byteBufferBitmapDecoder))
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
InputStream.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources,streamBitmapDecoder))
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
ParcelFileDescriptor.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources,parcelFileDescriptorVideoDecoder))
.append(BitmapDrawable.class,new BitmapDrawableEncoder(bitmapPool,bitmapEncoder))
/* GIFs */
.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())
/* GIF Frames */
// Compilation with Gradle requires the type to be specified for UnitModelLoader here.
.append(
GifDecoder.class,GifDecoder.class,UnitModelLoader.Factory.<GifDecoder>getInstance())
.append(
Registry.BUCKET_BITMAP,
GifDecoder.class,
Bitmap.class,
new GifFrameResourceDecoder(bitmapPool))
/* Drawables */
.append(Uri.class,Drawable.class,resourceDrawableDecoder)
.append(
Uri.class,Bitmap.class,new ResourceBitmapDecoder(resourceDrawableDecoder,bitmapPool))
/* Files */
.register(new ByteBufferRewinder.Factory())
.append(File.class,ByteBuffer.class,new ByteBufferFileLoader.Factory())
.append(File.class,InputStream.class,new FileLoader.StreamFactory())
.append(File.class,File.class,new FileDecoder())
.append(File.class,ParcelFileDescriptor.class,new FileLoader.FileDescriptorFactory())
// Compilation with Gradle requires the type to be specified for UnitModelLoader here.
.append(File.class,File.class,UnitModelLoader.Factory.<File>getInstance())
/* Models */
.register(new InputStreamRewinder.Factory(arrayPool))
.append(int.class,InputStream.class,resourceLoaderStreamFactory)
.append(
int.class,
ParcelFileDescriptor.class,
resourceLoaderFileDescriptorFactory)
.append(Integer.class,InputStream.class,resourceLoaderStreamFactory)
.append(
Integer.class,
ParcelFileDescriptor.class,
resourceLoaderFileDescriptorFactory)
.append(Integer.class,Uri.class,resourceLoaderUriFactory)
.append(
int.class,
AssetFileDescriptor.class,
resourceLoaderAssetFileDescriptorFactory)
.append(
Integer.class,
AssetFileDescriptor.class,
resourceLoaderAssetFileDescriptorFactory)
.append(int.class,Uri.class,resourceLoaderUriFactory)
.append(String.class,InputStream.class,new DataUrlLoader.StreamFactory())
.append(String.class,InputStream.class,new StringLoader.StreamFactory())
.append(String.class,ParcelFileDescriptor.class,new StringLoader.FileDescriptorFactory())
.append(
String.class,AssetFileDescriptor.class,new StringLoader.AssetFileDescriptorFactory())
.append(Uri.class,InputStream.class,new HttpUriLoader.Factory())
.append(Uri.class,InputStream.class,new AssetUriLoader.StreamFactory(context.getAssets()))
.append(
Uri.class,
ParcelFileDescriptor.class,
new AssetUriLoader.FileDescriptorFactory(context.getAssets()))
.append(Uri.class,InputStream.class,new MediaStoreImageThumbLoader.Factory(context))
.append(Uri.class,InputStream.class,new MediaStoreVideoThumbLoader.Factory(context))
.append(
Uri.class,
InputStream.class,
new UriLoader.StreamFactory(contentResolver))
.append(
Uri.class,
ParcelFileDescriptor.class,
new UriLoader.FileDescriptorFactory(contentResolver))
.append(
Uri.class,
AssetFileDescriptor.class,
new UriLoader.AssetFileDescriptorFactory(contentResolver))
.append(Uri.class,InputStream.class,new UrlUriLoader.StreamFactory())
.append(URL.class,InputStream.class,new UrlLoader.StreamFactory())
.append(Uri.class,File.class,new MediaStoreFileLoader.Factory(context))
.append(GlideUrl.class,InputStream.class,new HttpGlideUrlLoader.Factory())
.append(byte[].class,ByteBuffer.class,new ByteArrayLoader.ByteBufferFactory())
.append(byte[].class,InputStream.class,new ByteArrayLoader.StreamFactory())
.append(Uri.class,Uri.class,UnitModelLoader.Factory.<Uri>getInstance())
.append(Drawable.class,Drawable.class,UnitModelLoader.Factory.<Drawable>getInstance())
.append(Drawable.class,Drawable.class,new UnitDrawableDecoder())
/* Transcoders */
.register(
Bitmap.class,
BitmapDrawable.class,
new BitmapDrawableTranscoder(resources))
.register(Bitmap.class,byte[].class,bitmapBytesTranscoder)
.register(
Drawable.class,
byte[].class,
new DrawableBytesTranscoder(
bitmapPool,bitmapBytesTranscoder,gifDrawableBytesTranscoder))
.register(GifDrawable.class,byte[].class,gifDrawableBytesTranscoder);
直接讲解
这段代码是 无意义
的,我们从 Register
类入手,分析注册的内容。
public class Registry {
public static final String BUCKET_GIF = "Gif";
public static final String BUCKET_BITMAP = "Bitmap";
public static final String BUCKET_BITMAP_DRAWABLE = "BitmapDrawable";
private static final String BUCKET_PREPEND_ALL = "legacy_prepend_all";
private static final String BUCKET_APPEND_ALL = "legacy_append";
private final ModelLoaderRegistry modelLoaderRegistry;
private final EncoderRegistry encoderRegistry;
private final ResourceDecoderRegistry decoderRegistry;
private final ResourceEncoderRegistry resourceEncoderRegistry;
private final DataRewinderRegistry dataRewinderRegistry;
private final TranscoderRegistry transcoderRegistry;
private final ImageHeaderParserRegistry imageHeaderParserRegistry;
private final ModelToResourceClassCache modelToResourceClassCache =
new ModelToResourceClassCache();
private final LoadPathCache loadPathCache = new LoadPathCache();
private final Pool<List<Throwable>> throwableListPool = FactoryPools.threadSafeList();
public Registry() {
this.modelLoaderRegistry = new ModelLoaderRegistry(throwableListPool);
this.encoderRegistry = new EncoderRegistry();
this.decoderRegistry = new ResourceDecoderRegistry();
this.resourceEncoderRegistry = new ResourceEncoderRegistry();
this.dataRewinderRegistry = new DataRewinderRegistry();
this.transcoderRegistry = new TranscoderRegistry();
this.imageHeaderParserRegistry = new ImageHeaderParserRegistry();
setResourceDecoderBucketPriorityList(
Arrays.asList(BUCKET_GIF, BUCKET_BITMAP, BUCKET_BITMAP_DRAWABLE));
}
//API略去
}
资源Model加载器
modelLoaderRegistry
用于注册 资源Model加载方式
信息。例如,资源的定义Model为 Uri
类,注册一个 ModelLoaderFactory
,生产对应的
ModelLoader
,将 Uri
媒体实体,加载为 InputStream
或者其他形式的 内容
相关类:
ModelLoaderFactory
ModelLoader
等
编码器
encoderRegistry
用于注册 内容encode方式
信息。例如,媒体实体已被加载为 InputStream
,注册一个对应处理的 Encoder<InputStream>
,
用于处理内容的encode,如写入磁盘过程
相关类:Encoder
接口及其实现类
相应的,resourceEncoderRegistry
用于注册 Resource 的encode方式
,这些encoder面向 Resource
,相比于 InputStream
等低级形式的编码内容封装,
Resource
实现类进行了更高级别的编码内容封装。
相关类:
ResourceEncoder
接口及其实现类Resource
接口及其实现类EncodeStrategy
不难理解:媒体资源的数据封装存在不同 层级
:
- 读取数据的InputSteam
- Bitmap,BitmapDrawable
所以 encode过程 对不同层级的封装类,有不同的处理,当然,encoder可以通过 wrapper
,adapter
,transfer
等形式,利用其它encoder扩展功能
解码器
decoderRegistry
用于注册 媒体数据解码为Resource方式
的信息。
前面我们提到 modelLoaderRegistry
注册的信息中,可以得到 ModelLoader
, 它们负责将 资源Model
加载为 资源内容
,这种 资源内容
以 InputStream
等低级形式存在即可。
不难理解,这可以有效的解决 类数量爆炸
问题。
脑暴:假定 Model 的类数量为m个,解码后输出的形式有n个
- 不采用这种方式处理,一共需要 m*n 个 decoder 类
- 采用这种方式处理,一共需要 m+n 个 decoder 类
当
层级
增加时,差距会更加明显按照经验推断,Glide在处理decode过程时,采用了
Wrapper/delegate
模式 或者bridge
模式。
思变:项目中是否可以使用类似方式,处理不同层级之间
数据Bean
的转化
或者包装
?
相关类:
ResourceDecoder
及其实现类Resource
及其实现类
转换器
虽然直译为转码器,但是容易概念混淆,按照其功能称为转换器
transcoderRegistry
用于注册 转化器,及其负责的原始类型和转换类型
信息,转换器将资源从一种形式转换为另一种形式。例如: Bitmap -> byte[]
相关类:
ResourceTranscoder
及其实现类Resource
及其实现类
头信息解析器
imageHeaderParserRegistry
用于注册 头信息解析器
信息
注,部分操作系统为了更简便的决定文件的处理方式,利用了文件扩展名。但文件实质内容的编码方式信息,存储在文件头信息中,又称: File Sigs
、文件魔数
。
例如 FF D8 代表 Generic JPEG image file,即 JPE, JPEG, JPG
相关类:
ImageHeaderParser
及其实现类ImageType
模块职责总结
通过前文的分析,并查阅Glide源码,我们可以对模块职责进行一次初步总结。
在之后的文章中,我们将对具体模块进行 更细致
的挖掘,此处总结的类信息,就是 突破口
。
考虑到目前收集的信息 并不全面
,我不打算绘制一个图,下面的信息也 并非
十分重要,所以将其作为一个 临时的备忘录
即可。
在后续内容中,我会对各个模块单独总结成图
下一篇,我们将对 资源Model加载、获取流程
进行 深度挖掘
。
缓存与池
- MemorySizeCalculator
- LruBitmapPool
- BitmapPoolAdapter
- LruArrayPool
- LruResourceCache
- InternalCacheDiskCacheFactory
资源获取
- RequestManagerRetriever
- RequestManager
- RequestBuilder
- Request
- DefaultConnectivityMonitorFactory
核心流程
- Engine
其他信息尚不能确定。主要流程的相关信息如下:
资源Model加载器
ModelLoaderFactory
ModelLoader
等
编码器
Encoder
接口及其实现类ResourceEncoder
接口及其实现类Resource
接口及其实现类EncodeStrategy
解码器
ResourceDecoder
及其实现类Resource
及其实现类
转换器
ResourceTranscoder
及其实现类Resource
及其实现类
头信息解析器
ImageHeaderParser
及其实现类ImageType
线程池
- GlideExecutor
Glide的创建与配置
GlideBuilder
用于创建,com.bumptech.glide.module
包下的内容用于自定义模块,诸如:
AppGlideModule
LibraryGlideModule
以及一些已废弃的内容,不再赘述
思危、思退、思变
可能有读者习惯性地拉到尾部,前面提到,结尾处的大篇幅内容都是 备忘录
性质,而且之后的系列文章会在这些内容的基础上展开,可读可不读
但既然拉到了这里,就思考一下吧,阅读优秀的框架,不仅仅可以深入了解框架内容,也可以锻炼设计能力:
- 思危:使用GlideBuilder构建Glide实例是否有没有注意到的危险?
- 思危:项目中再次对Glide实现单例是否存在危险?
- 思变:项目中是否存在可以借鉴Glide的设计思路的地方?