Glide中优秀代码总结

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中。

策略模式

DiskCacheStrategy代表的是硬盘缓存策略,先看下DiskCacheStrategy抽象类有哪几个方法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public abstract class DiskCacheStrategy {
  //是否可以存储原始图片到磁盘中
  public abstract boolean isDataCacheable(DataSource dataSource);
  //是否可以存储解码后的图片到磁盘中
  public abstract boolean isResourceCacheable(
    boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy);
  //是否可以获取磁盘中解码后的图片缓存
  public abstract boolean decodeCachedResource();
  //是否可以获取磁盘中原始图片缓存
  public abstract boolean decodeCachedData();
}

其中DiskCacheStrategy的子类有5种,它们都定义在DiskCacheStrategy抽象类中。分别是ALL、NONE、DATA、RESOURCE、AUTOMATIC这5种策略。拿ALL来说:

 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
public static final DiskCacheStrategy ALL =
    new DiskCacheStrategy() {
      @Override
      public boolean isDataCacheable(DataSource dataSource) {
        //如果图片来自于网络则直接存储原始图片到磁盘中
        return dataSource == DataSource.REMOTE;
      }

      @Override
      public boolean isResourceCacheable(
          boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
            //如果图片不是来自解码后的磁盘缓存并且不是来自内存缓存则可以存储解码后的图片到磁盘中
        return dataSource != DataSource.RESOURCE_DISK_CACHE
            && dataSource != DataSource.MEMORY_CACHE;
      }

      @Override
      public boolean decodeCachedResource() {
        //可以获取磁盘中解码后的图片缓存
        return true;
      }

      @Override
      public boolean decodeCachedData() {
        //可以获取磁盘中原始图片缓存
        return true;
      }
    };

glide中默认使用的策略是AUTOMATIC。它和上面的ALL区别是isResourceCacheable方法,也就是是否存储解码后的图片到磁盘中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public static final DiskCacheStrategy AUTOMATIC =
    new DiskCacheStrategy() {
      @Override
      public boolean isResourceCacheable(
          boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy) {
        return ((isFromAlternateCacheKey && dataSource == DataSource.DATA_DISK_CACHE)
                || dataSource == DataSource.LOCAL)
            && encodeStrategy == EncodeStrategy.TRANSFORMED;
      }
    }

如果是加载缩略图并且资源来自于磁盘原始数据,或者资源来自于本地资源。并且带有转换的策略,也就是会经过缩放、裁切,举例说明:

  • 本地资源+已转换
    1
    2
    3
    4
    5
    
    // 例如:加载本地图片并进行了裁剪
    Glide.with(context)
      .load(R.drawable.local_image)  // DataSource.LOCAL
      .circleCrop()                  // TRANSFORMED 转换
      .into(imageView);              // 会缓存转换后的结果
    
  • 从原始缓存生成缩略图+已转换
    1
    2
    3
    4
    5
    6
    
    // 缩略图场景,从已缓存的原始数据生成
    Glide.with(context)
      .load(url)
      .thumbnail(0.1f)              // 可能触发 isFromAlternateCacheKey
      .circleCrop()                  // TRANSFORMED 转换
      .into(imageView);
    
  • 比如加载网络的资源就不缓存解码后的图片:
    1
    2
    3
    4
    
    // 网络图片默认不会缓存转换后的结果
    Glide.with(context)
      .load("http://example.com/image.jpg")  // DataSource.REMOTE
      .into(imageView);                      // 不缓存转换后结果
    
  • 加载本地资源的时候,未经转换:
    1
    2
    3
    4
    5
    
    // 本地图片但没有转换操作
    Glide.with(context)
      .load(R.drawable.local_image)  // DataSource.LOCAL
      // 没有转换操作,encodeStrategy 可能不是 TRANSFORMED
      .into(imageView);              // 可能不缓存
    

Transformation自带的transform也是一种策略体现

1
2
3
4
public interface Transformation<T> extends Key {
  Resource<T> transform(
      @NonNull Context context, @NonNull Resource<T> resource, int outWidth, int outHeight);
}

在RequestBuilder的into方法中构造不同的Transformation,有CenterCrop、CenterInside、FitCenter这几类都是属于Transformation接口。

装饰者模式

装饰者模式都是在不修改原有类的结构情况下,通过装饰者类来给原来类添加功能的一种模式。装饰者和被装饰者实现同一个接口,对于客户端调用来说,它是通过装饰者类调用被装饰对象。

  • DrawableTransformation
 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
public class DrawableTransformation implements Transformation<Drawable> {
  private final Transformation<Bitmap> wrapped;
  public Resource<Drawable> transform(
      @NonNull Context context, @NonNull Resource<Drawable> resource, int outWidth, int outHeight) {
    BitmapPool bitmapPool = Glide.get(context).getBitmapPool();
    Drawable drawable = resource.get();
    Resource<Bitmap> bitmapResourceToTransform =
        DrawableToBitmapConverter.convert(bitmapPool, drawable, outWidth, outHeight);
    if (bitmapResourceToTransform == null) {
      if (isRequired) {
        throw new IllegalArgumentException("Unable to convert " + drawable + " to a Bitmap");
      } else {
        return resource;
      }
    }
    Resource<Bitmap> transformedBitmapResource =
        wrapped.transform(context, bitmapResourceToTransform, outWidth, outHeight);

    if (transformedBitmapResource.equals(bitmapResourceToTransform)) {
      transformedBitmapResource.recycle();
      return resource;
    } else {
      return newDrawableResource(context, transformedBitmapResource);
    }
  }
}

在上面DrawableTransformation中wrapped是一个被装饰的Transformation对象,而DrawableTransformation本身它只会将Drawable类型的资源转化成Bitmap,等到被装饰的wrapped对象完成转化后,接着又将bitmap转回到drawable。DrawableTransformation是在传入Uri类型的model时候,然后解码返回的drawable类型的数据,接着通过DrawableTransformation完成transform过程。

责任链模式

transform 可以无限叠加,比如:transform(CenterCrop(), RoundedCorners()),会将所有的 Transformation 放到 MultiTransformation 中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class MultiTransformation<T> implements Transformation<T> {
  private final Collection<? extends Transformation<T>> transformations;

  public Resource<T> transform(
      @NonNull Context context, @NonNull Resource<T> resource, int outWidth, int outHeight) {
    Resource<T> previous = resource;
    for (Transformation<T> transformation : transformations) {
      Resource<T> transformed = transformation.transform(context, previous, outWidth, outHeight);
      if (previous != null && !previous.equals(resource) && !previous.equals(transformed)) {
        previous.recycle();
      }
      previous = transformed;
    }
    return previous;
  }
}

责任链模式的核心特征:

  1. 链式处理:每个 Transformation 依次处理前一个的输出结果
  2. 依次传递:数据像链条一样依次传递给下一个处理器
  3. 灵活组合:可以任意组合多个 Transformation,形成处理链

与迭代器模式的区别:

  • 迭代器模式只负责遍历,不关心处理逻辑
  • 责任链模式不仅遍历,还要让每个处理器处理数据并传递

与组合模式的区别:

  • 组合模式强调"整体-部分"的树形层次结构
  • 责任链模式强调线性的处理流程,数据沿链传递

代理模式

在StringLoader中持有了另外一个ModelLoader,当uriLoader的handles方法通过后,才会去去执行uriLoader的buildLoadData方法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class StringLoader<Data> implements ModelLoader<String, Data> {
  private final ModelLoader<Uri, Data> uriLoader;
  @Override
  public LoadData<Data> buildLoadData(
      @NonNull String model, int width, int height, @NonNull Options options) {
    Uri uri = parseUri(model);
    if (uri == null || !uriLoader.handles(uri)) {
      return null;
    }
    return uriLoader.buildLoadData(uri, width, height, options);
  }
}

这是一个静态代理模式的体现,在静态代码中代理类主要控制被代理类的访问权限,此处通过判断uriLoader的handles方法是否通过,如果通过的话,才会去访问uriLoader这个被代理类。这也正符合静态代理模式的特征,主要是控制被代理类的访问权限。

组合模式

通过根结点包含子节点来达到组合模式,其中根结点和子节点实现共同的接口。以表示整体和部分的关系,比如在MultiModelLoader中包含了ModelLoader的集合:

 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
class MultiModelLoader<Model, Data> implements ModelLoader<Model, Data> {
  private final List<ModelLoader<Model, Data>> modelLoaders;
  @Override
  public LoadData<Data> buildLoadData(
      @NonNull Model model, int width, int height, @NonNull Options options) {
    Key sourceKey = null;
    int size = modelLoaders.size();
    List<DataFetcher<Data>> fetchers = new ArrayList<>(size);
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0; i < size; i++) {
      ModelLoader<Model, Data> modelLoader = modelLoaders.get(i);
      if (modelLoader.handles(model)) {
        LoadData<Data> loadData = modelLoader.buildLoadData(model, width, height, options);
        if (loadData != null) {
          sourceKey = loadData.sourceKey;
          fetchers.add(loadData.fetcher);
        }
      }
    }
    return !fetchers.isEmpty() && sourceKey != null
        ? new LoadData<>(sourceKey, new MultiFetcher<>(fetchers, exceptionListPool))
        : null;
  }

  @Override
  public boolean handles(@NonNull Model model) {
    for (ModelLoader<Model, Data> modelLoader : modelLoaders) {
      if (modelLoader.handles(model)) {
        return true;
      }
    }
    return false;
  }
}

适配器模式

适配器模式主要是将目标类的接口适配成业务需要的接口,被适配类和适配器无需实现同一个接口,适配类持有了被适配接口引用或对象引用。

  • Target接口
 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
//适配接口
public interface Target<R> extends LifecycleListener {
  void onLoadStarted(@Nullable Drawable placeholder);
  void onLoadFailed(@Nullable Drawable errorDrawable);
  void onResourceReady(@NonNull R resource, @Nullable Transition<? super R> transition);
  void onLoadCleared(@Nullable Drawable placeholder);
}

//适配 ImageView 的基础类
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>
    implements Transition.ViewAdapter {
      //在适配器类中持有了ImageView被适配对象
      public ImageViewTarget(ImageView view) {
        super(view);
      }

  @Override
  public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
    if (transition == null || !transition.transition(resource, this)) {
      //子类中去调用imageView的setImageBitmap的方法
      setResourceInternal(resource);
    } else {
      maybeUpdateAnimatable(resource);
    }
  }    
}

桥接模式

桥接模式主要是将主体作为抽象和实现进行分离,这样抽象能和实现随意组合,互相不影响。在glide中使用桥接模式主要体现在ModelLoader和DataFetcher之间的联系,ModelLoader作为数据输入和输出的抽象定义,DataFetcher作为数据加载的实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public interface ModelLoader<Model, Data> {
  @Nullable
  LoadData<Data> buildLoadData(
      @NonNull Model model, int width, int height, @NonNull Options options);
  boolean handles(@NonNull Model model);
}

public interface DataFetcher<T> {
  void loadData(@NonNull Priority priority, @NonNull DataCallback<? super T> callback);
}

他两看似没有什么联系,中间通过loadData进行关联上,loadData中持有了对应的DataFetcher,比如通过url的地址请求图片的时候通过StringLoader和HttpUrlFetcher进行组合,StringLoader中指定了modelClass是String.class,dataClass是InputStream.class,而HttpUrlFetcher则是最终实现网络请求的实现角色。通过中间的LoadData进行桥接。

Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计