返回

源码角度剖析Glide4缓存

Android

Glide是Android平台上最受欢迎的图片加载库之一,它提供了强大的缓存机制来优化图片加载性能。Glide的缓存机制分为三级:内存缓存、磁盘缓存和网络缓存。

内存缓存是Glide中最快的缓存层,它将最近加载的图片存储在内存中,以便下次加载时可以直接从内存中读取。磁盘缓存是Glide的第二层缓存,它将图片存储在磁盘上,以便在内存缓存中找不到图片时从磁盘中加载。网络缓存是Glide的第三层缓存,它将图片存储在网络上,以便在磁盘缓存中找不到图片时从网络上加载。

Glide使用EngineKey来管理缓存。EngineKey是缓存的唯一标识符,它包含了图片的URL、图片的尺寸、图片的格式等信息。当Glide需要加载一张图片时,它会首先检查内存缓存中是否有这张图片。如果没有,则会检查磁盘缓存中是否有这张图片。如果没有,则会从网络上加载这张图片。当Glide将图片加载到内存缓存或磁盘缓存中时,它会将EngineKey作为缓存的唯一标识符。这样,当Glide下次需要加载这张图片时,它就可以直接使用EngineKey来查找缓存。

Glide的缓存机制可以显著提高图片加载性能。通过使用内存缓存、磁盘缓存和网络缓存,Glide可以避免重复加载相同的图片,从而减少网络流量和提高加载速度。

下面是Glide缓存机制的源码实现:

public class EngineKeyFactory {

  public EngineKey buildKey(Key signature, WidthHeightOptions widthHeightOptions, Map<Class<?>, Transformation<?>> transformations) {
    return new EngineKey(signature, widthHeightOptions, transformations);
  }
}

public class EngineKey {

  private final Key signature;
  private final WidthHeightOptions widthHeightOptions;
  private final Map<Class<?>, Transformation<?>> transformations;

  public EngineKey(Key signature, WidthHeightOptions widthHeightOptions,
      Map<Class<?>, Transformation<?>> transformations) {
    this.signature = signature;
    this.widthHeightOptions = widthHeightOptions;
    this.transformations = transformations;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    EngineKey engineKey = (EngineKey) o;

    if (!signature.equals(engineKey.signature)) return false;
    if (!widthHeightOptions.equals(engineKey.widthHeightOptions)) return false;
    return transformations.equals(engineKey.transformations);
  }

  @Override
  public int hashCode() {
    int result = signature.hashCode();
    result = 31 * result + widthHeightOptions.hashCode();
    result = 31 * result + transformations.hashCode();
    return result;
  }
}

public class GlideBitmapDecoder implements ResourceDecoder<GlideUrl, Bitmap> {

  @Override
  public Resource<Bitmap> decode(GlideUrl source, int width, int height, Options options)
      throws IOException {
    SourceFetcher fetcher = buildSourceFetcher(source, width, height);
    return decodeSource(fetcher, width, height, options);
  }

  protected Resource<Bitmap> decodeSource(SourceFetcher fetcher, int width, int height,
      Options options) throws IOException {
    InputStream is = fetcher.loadData(priority).getStream();
    try {
      return decodeSource(is, width, height, options);
    } finally {
      is.close();
    }
  }

  protected Resource<Bitmap> decodeSource(InputStream is, int width, int height, Options options) {
    Bitmap bitmap = BitmapFactory.decodeStream(is, null, options.inBitmap);
    return BitmapResource.obtain(bitmap, options.pool);
  }

  @Override
  public boolean handles(GlideUrl source, Options options) {
    return true;
  }
}

public class SourceDecoder<T, R> implements ResourceDecoder<T, R> {

  private final DataFetcherFactory<T, R> dataFetcherFactory;

  public SourceDecoder(DataFetcherFactory<T, R> dataFetcherFactory) {
    this.dataFetcherFactory = dataFetcherFactory;
  }

  @Override
  public Resource<R> decode(T source, int width, int height, Options options)
      throws IOException {
    DataFetcher<R> fetcher = dataFetcherFactory.buildDataFetcher(source, width, height, options);
    R data = fetcher.loadData(priority).get();
    return new SimpleResource<>(data);
  }

  @Override
  public boolean handles(T source, Options options) {
    return dataFetcherFactory.handles(source);
  }
}

public interface DataFetcher<T> {

  DataFetcherResult<T> loadData(Priority priority) throws Exception;
}

public class GlideUrl {

  private final String url;

  public GlideUrl(String url) {
    this.url = url;
  }

  public String getUrl() {
    return url;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    GlideUrl glideUrl = (GlideUrl) o;

    return url.equals(glideUrl.url);
  }

  @Override
  public int hashCode() {
    return url.hashCode();
  }
}

public class Request {

  private final Object model;
  private final RequestListener<R> requestListener;

  public Request(Object model, RequestListener<R> requestListener) {
    this.model = model;
    this.requestListener = requestListener;
  }

  public Object getModel() {
    return model;
  }

  public RequestListener<R> getRequestListener() {
    return requestListener;
  }
}

public interface Target {

  void onResourceReady(Resource<?> resource, Transition<? super Resource<?>> transition);

  void onLoadFailed(@Nullable Drawable errorDrawable);

  void onLoadCleared(@Nullable Drawable placeholder);

  void getSize(SizeReadyCallback cb);

  void removeCallback(SizeReadyCallback cb);
}