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
|
private static volatile Glide glide;
public static Glide get(@NonNull Context context) {
if (glide == null) {
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
private static volatile boolean isInitializing;
static void checkAndInitializeGlide(
@NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
if (isInitializing) {
throw new IllegalStateException(
"Glide has been called recursively, this is probably an internal library error!");
}
isInitializing = true;
try {
initializeGlide(context, generatedAppGlideModule);
} finally {
isInitializing = false;
}
}
|
上面Glide对象初始化使用DCL双重锁判断,并且checkAndInitializeGlide方法中使用了isInitializing变量表示是否正在初始化。这个isInitializing变量解决单线程递归调用Glide.get方法会创建多个Glide实例。因为在DCL模式中,单线程是能重入synchronized锁的。为了避免单线程能多次创建Glide实例,所以加了标志表示是否正在加载。
Builder建造者模式
建造者模式是属于创建型中的一种,用于创建复杂对象,将对象的构建与表示分离,以便相同的构建过程可以创建不同的表示。
- GlideBuilder
- 用于创建Glide对象,因为Glide对象比较复杂,所以将Glide的创建交给了GlideBuilder,同样的构建过程,可以表示不同的Glide对象。比如指定sourceExecutor(加载网络资源的线程池)、diskCacheExecutor(加载本地磁盘缓存的线程池)等。
- RequestBuilder
- 它是继承自BaseRequestOptions,因此在构建request过程中,它是充当了builder创建模式来创建request,比如配置override大小、placeholder等。
原型模式
RequestBuilder的clone
在RequestBuilder中的into方法里面每次先clone一份RequestOptions出来:
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
|
class RequestBuilder{
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
}
}
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/* targetListener= */ null,
requestOptions,
Executors.mainThreadExecutor());
}
public T clone() {
try {
BaseRequestOptions<?> result = (BaseRequestOptions<?>) super.clone();
result.options = new Options();
result.options.putAll(options);
result.transformations = new CachedHashCodeArrayMap<>();
result.transformations.putAll(transformations);
result.isLocked = false;
result.isAutoCloneEnabled = false;
return (T) result;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
|
requestOptions通过clone方法构造一个新的BaseRequestOptions,原型模式的作用是通过已有的对象属性构建一个新的对象,好处是创建新对象时复用已有配置,避免重复设置。新对象与原对象相互独立,互不影响。此处好处有如下几点:
- 支持 RequestBuilder 复用
- RequestBuilder是可以复用的,因为load方法会返回requestBuilder,而into可以作用到不同的imageView上,如果先作用到imageView1上,它的scaleType是fitCenter,而后又作用到imageView2上,此时imageView是centerCrop模式展示。如果没有clone的话,imageView2加载完后会影响到imageView1的展示。因为scaleType的不同会给requestOptions设置strategy和transformation不同。
- 防止后续修改影响已发起的请求
- 还是拿两个图片共用一个RequestBuilder来说,比如imageView1需要通过requestOptions设置override(100,100)的大小,此时imageView1还在请求,而此时imageView2通过requestOptions设置override(200,200),那么此时如果没有clone出一个新的requestOptions会导致imageView1加载的大小不对应。
- 多线程安全问题
- into方法如果在不同的线程被调用,如果没有clone出一个新的requestOptions,那么会存在线程安全问题。
工厂模式
DiskCache的创建
glide中使用的工厂模式分为工厂方法模式和抽象工厂模式,首先看下哪些地方用到了工厂方法模式:
- DiskCache的创建
- 在GlideBuilder中默认初始化了DiskCache.Factory,他其实是一个InternalCacheDiskCacheFactory:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public interface DiskCache {
interface Factory {
@Nullable
DiskCache build();
}
}
public final class GlideBuilder {
private DiskCache.Factory diskCacheFactory;
Glide build(){
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
}
}
|
接着将diskCacheFactory给到Engine,在Engine中会将diskCacheFactory给到LazyDiskCacheProvider,它是实现了DecodeJob.DiskCacheProvider接口,可以看出来它是在DecodeJob中需要使用到该DiskCache.Factory,我们设计接口的时候,需要将接口保持最小范围,如果只在外部类中使用该接口,将接口定义在外部类中,体现了设计原则中的封装原则,从而减少对外暴露。第二点体现了高内聚原则,将相关的接口和类放在一起,提高内聚性。
1
2
3
4
5
|
class DecodeJob{
interface DiskCacheProvider {
DiskCache getDiskCache();
}
}
|
并且LazyDiskCacheProvider的定义是在Engine中定义,这也体现了高内聚和封装原则,不仅是接口,类与类之间也能体现出来:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
class Engine{
private static class LazyDiskCacheProvider implements DecodeJob.DiskCacheProvider {
private final DiskCache.Factory factory;
private volatile DiskCache diskCache;
LazyDiskCacheProvider(DiskCache.Factory factory) {
this.factory = factory;
}
@Override
public DiskCache getDiskCache() {
if (diskCache == null) {
synchronized (this) {
if (diskCache == null) {
diskCache = factory.build();
}
if (diskCache == null) {
diskCache = new DiskCacheAdapter();
}
}
}
return diskCache;
}
}
}
|
LazyDiskCacheProvider从字面意思也能看出来,它是一个延迟获取DiskCache的封装类。如果没有它,那就得在Glide初始化的时候创建DiskCache了。因为DiskCache是一个重量级的类,里面涉及到文件目录的创建等。并且在LazyDiskCacheProvider中保证了线程安全来创建DiskCache。
RequestOptions的创建
1
2
3
4
5
6
|
class Glide{
public interface RequestOptionsFactory {
@NonNull
RequestOptions build();
}
}
|
它是在Glide外部类中定义的接口,也是和上面类似,再来看下它的接口实现类:
1
2
3
4
5
6
7
8
9
10
|
class GlideBuilder{
private RequestOptionsFactory defaultRequestOptionsFactory =
new RequestOptionsFactory() {
@NonNull
@Override
public RequestOptions build() {
return new RequestOptions();
}
};
}
|
在Glide创建的时候,直接把defaultRequestOptionsFactory传给了Glide对象,也没有判断外界有没有传入RequestOptionsFactory,可以看出来它无需外界进行扩展,这点和DiskCache.Factory不太一样。由于RequestOptions是一个轻量级的,所以它也无需延迟初始化,它是在RequestManager初始化中调用GlideContext的getDefaultRequestOptions方法来创建的:
1
2
3
4
5
6
7
8
|
class GlideContext{
public synchronized RequestOptions getDefaultRequestOptions() {
if (defaultRequestOptions == null) {
defaultRequestOptions = defaultRequestOptionsFactory.build().lock();
}
return defaultRequestOptions;
}
}
|
Registry的创建
- Registry是通过GlideSupplier接口创建的,也是一个工厂方法模式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public final class GlideSuppliers {
public interface GlideSupplier<T> {
T get();
}
private GlideSuppliers() {}
public static <T> GlideSupplier<T> memorize(final GlideSupplier<T> supplier) {
return new GlideSupplier<T>() {
private volatile T instance;
@Override
public T get() {
if (instance == null) {
synchronized (this) {
if (instance == null) {
instance = Preconditions.checkNotNull(supplier.get());
}
}
}
return instance;
}
};
}
}
|
也是一个类中内部接口,不过该接口是一个泛型。外界需要调用memorize方法,并传入一个GlideSupplier的实现类,在前面介绍Registry创建过程中,它是在GlideContext的getRegistry方法进行获取的,而默认是调用memorize方法获取到GlideSupplier对象,等到需要Registry时候才会调用GlideSupplier的get方法,显而易见这是一个延迟初始化,并且这里使用了静态代理,将Registry的最终获取交给了外界传入的Registry。同时匿名内部类的GlideSupplier通过双重锁保证了线程安全,这里其实和上面的DiskCache的创建有点异曲同工之妙。
ModelLoader的创建
- ModelLoader是通过ModelLoaderFactory接口来创建的:
1
2
3
4
|
public interface ModelLoaderFactory<T, Y> {
@NonNull
ModelLoader<T, Y> build(@NonNull MultiModelLoaderFactory multiFactory);
}
|
在RegistryFactory中先把modelClass、dataClass、ModelLoaderFactory注册到MultiModelLoaderFactory中,组转成一个个的Entry对象,等到要使用ModelLoader时候,通过modelClass和dataClass过滤出ModelLoaderFactory,然后通过ModelLoaderFactory创建出ModelLoader,接着获取到LoadData,最后获取到DataFetcher。
在MultiModelLoader中装载了ModelLoader的集合,包含了多个子节点,在获取LoadData的时候使用了责任链模式,依次让每个ModelLoader尝试进行获取LoadData,同时这里也体现出了迭代器模式。
DataRewinder的创建
- DataRewinder是一个数据重置器,它也是通过方法工厂来创建的
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public interface DataRewinder<T> {
interface Factory<T> {
@NonNull
DataRewinder<T> build(@NonNull T data);
@NonNull
Class<T> getDataClass();
}
@NonNull
T rewindAndGet() throws IOException;
}
|
也是在外部接口中定义内部接口。在前面介绍InputStream转化成File的时候讲过,先把各种DataRewinder.Factory注册到DataRewinderRegistry中,然后通过传入的class类型获取到对应的DataRewinder.Factory,接着通过build方法获取到DataRewinder。
Encoder的获取
Encoder是编码器的接口类,Encoder的创建虽然没有用到Factory,但是它是和上面DataRewinder的创建形成了对比,Encoder它是直接在Registry阶段直接包转成Entry,然后在获取的时候直接从Entry中获取到Encoder。
Encoder为什么它不需要Factory创建呢?而DataRewinder需要通过Factory来创建?
| 特性 |
Encoder |
DataRewinder |
| 状态 |
无状态 |
有状态 |
| 数据依赖 |
数据通过方法参数传入 |
数据在构造时注入 |
| 实例复用 |
✅ 可复用,一个实例处理多个请求 |
❌ 每次需要新实例 |
| 生命周期 |
应用级别,长期存活 |
请求级别,用完释放 |
| 资源管理 |
不需要 cleanup |
需要 cleanup() 释放资源 |
比如在前面讲的将原始图片保存到本地的时候说过StreamEncoder:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class StreamEncoder implements Encoder<InputStream>{
public boolean encode(@NonNull InputStream data, @NonNull File file, @NonNull Options options) {
byte[] buffer = byteArrayPool.get(ArrayPool.STANDARD_BUFFER_SIZE_BYTES, byte[].class);
boolean success = false;
OutputStream os = new FileOutputStream(file);
int read;
while ((read = data.read(buffer)) != -1) {
os.write(buffer, 0, read);
}
os.close();
success = true;
byteArrayPool.put(buffer);
return success;
}
}
|
它不持有数据,所以是无状态的。数据是通过方法参数传入。并且StreamEncoder是应用级别的,它无需每次进行创建。所以它无需通过factory进行延迟初始化。而在DataRewinder中它是需要持有数据的,比如前面讲的InputStreamRewinder:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public final class InputStreamRewinder implements DataRewinder<InputStream> {
// 5MB.
private static final int MARK_READ_LIMIT = 5 * 1024 * 1024;
private final RecyclableBufferedInputStream bufferedStream;
@Synthetic
public InputStreamRewinder(InputStream is, ArrayPool byteArrayPool) {
bufferedStream = new RecyclableBufferedInputStream(is, byteArrayPool);
bufferedStream.mark(MARK_READ_LIMIT);
}
@NonNull
@Override
public InputStream rewindAndGet() throws IOException {
bufferedStream.reset();
return bufferedStream;
}
}
|
它需要持有数据,因为它需要多次对流进行重置位置。并且每次获取图片都需要创建一个新的DataRewinder,所以它需要通过factory来创建不同的DataRewinder,因为它是跟数据绑定在一块的,因此用到了延迟初始化。
解码(静态代理)
- 首先了解几个概念,dataClass:数据源类型,比如从网络获取的数据类型是byteBuffer.class类型。resourceClass:解码后的资源类型,比如bitmap的解码,它是BitmapDrawable.class,也就是bitmap的drawable包装。transcodeClass:最终转换类型,比如要展示到imageView上的时候,此时是Drawable.class类型。
- 在注册的时候,会按照bucket、dataClass、resourceClass、decoder四个参数组转成Entry,并且该Entry是定义在ResourceDecoderRegistry的私有内部类中。保证高内聚,低耦合。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
private static class Entry<T, R> {
private final Class<T> dataClass;
@Synthetic final Class<R> resourceClass;
@Synthetic final ResourceDecoder<T, R> decoder;
public Entry(
@NonNull Class<T> dataClass,
@NonNull Class<R> resourceClass,
ResourceDecoder<T, R> decoder) {
this.dataClass = dataClass;
this.resourceClass = resourceClass;
this.decoder = decoder;
}
public boolean handles(@NonNull Class<?> dataClass, @NonNull Class<?> resourceClass) {
return this.dataClass.isAssignableFrom(dataClass)
&& resourceClass.isAssignableFrom(this.resourceClass);
}
}
|
最终将这些Entry装载到ResourceDecoderRegistry的decoders这个map中。比如在前面介绍的BitmapDrawableDecoder,它就是按照bucket= “BitmapDrawable”,dataClass=“ByteBuffer.class”,resourceClass=“BitmapDrawable.class”,decoder=BitmapDrawableDecoder组成的entry来获取的。并且在BitmapDrawableDecoder中使用了代理模式,实际代理到ByteBufferBitmapDecoder,最终会调用到Downsampler中。