Glide之旅 —— Key

来源:互联网 发布:张利国java 编辑:程序博客网 时间:2024/06/07 22:13

前言

glide是谷歌推荐的Android图片加载框架,其优秀的缓存策略、Activity的生命周期的继承、GIF图片的支持等都是为人所称道的地方。下面是用glide加载一张图片的调用。

private void loadImage() {    Glide.with(this)         .load("http://pic2.orsoon.com/2017/0118/20170118011032176.jpg")         .into(ivTest);}

那么,该框架是如何实际运作的呢,我会通过“Glide之旅”系列博客尽可能详细地将我的心得记录下来。“Glide之旅”系列文章汇总:

  • Glide之旅 —— Registry

  • Glide之旅 —— Key

  • Glide之旅 —— DecodeJob

概述

Key(com.bumptech.glide.load.Key),顾名思义,是用来作为图片的唯一标识,那么具体又是怎样的呢?

已知实现类

Key是一个接口,其所有实现类有

  • com.bumptech.glide.load.resource.bitmap.BitmapDrawableTransformation

  • com.bumptech.glide.load.engine.prefill.BitmapPreFillRunner.UniqueKey

  • com.bumptech.glide.load.resource.bitmap.BitmapTransformation

  • com.bumptech.glide.load.resource.bitmap.CenterCrop

  • com.bumptech.glide.load.resource.bitmap.CenterInside

  • com.bumptech.glide.load.resource.bitmap.CircleCrop

  • com.bumptech.glide.load.engine.DataCacheKey

  • com.bumptech.glide.signature.EmptySignature

  • com.bumptech.glide.load.engine.EngineKey

  • com.bumptech.glide.load.resource.bitmap.FitCenter

  • com.bumptech.glide.load.resource.gif.GifDrawableTransformation

  • com.bumptech.glide.load.resource.gif.GifFrameLoader.FrameSignature

  • com.bumptech.glide.load.model.GlideUrl

  • com.bumptech.glide.signature.MediaStoreSignature

  • com.bumptech.glide.load.MultiTransformation<T>

  • com.bumptech.glide.signature.ObjectKey

  • com.bumptech.glide.load.Options

  • com.bumptech.glide.load.engine.ResourceCacheKey

  • com.bumptech.glide.load.resource.bitmap.RoundedCorners

  • com.bumptech.glide.load.resource.UnitTransformation<T>

GlideUrl

当调用前言中的loadImage()进行图片加载的时候,结合我的Glide之旅 —— DecodeJob一文中的源码流程可知,用SourceGenerator解码远程图片的时候,首先会执行到com.bumptech.glide.load.model.stream.HttpUriLoader.Factory#build(MultiModelLoaderFactory),先来看下源码

package com.bumptech.glide.load.model.stream;...public class HttpUriLoader implements ModelLoader<Uri, InputStream> {    ...    public static class Factory implements ModelLoaderFactory<Uri, InputStream> {        @Override        public ModelLoader<Uri, InputStream> build(MultiModelLoaderFactory multiFactory) {            return new HttpUriLoader(multiFactory.build(GlideUrl.class, InputStream.class));        }        @Override        public void teardown() {            // Do nothing.        }    }}

那么显然,根据Glide之旅 —— Registry中介绍的获取注册项方法可知,需要在ModelLoaderRegistry数据集合中找出Entry第一个传参为GlideUrl.class,第二个传参为InputStream.class的数据项,可知符合条件的有

23. new MultiModelLoaderFactory.Entry(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())

那么,此时再来看下com.bumptech.glide.load.model.stream.HttpGlideUrlLoader的源码

package com.bumptech.glide.load.model.stream;...public class HttpGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {    public static final Option<Integer> TIMEOUT = Option.memory(            "com.bumptech.glide.load.model.stream.HttpGlideUrlLoader.Timeout", 2500);    @Nullable    private final ModelCache<GlideUrl, GlideUrl> modelCache;    public HttpGlideUrlLoader() {        this(null);    }    public HttpGlideUrlLoader(ModelCache<GlideUrl, GlideUrl> modelCache) {        this.modelCache = modelCache;    }    @Override    public LoadData<InputStream> buildLoadData(GlideUrl model, int width, int height,                                               Options options) {        GlideUrl url = model;        if (modelCache != null) {            url = modelCache.get(model, 0, 0);            if (url == null) {                modelCache.put(model, 0, 0, model);                url = model;            }        }        int timeout = options.get(TIMEOUT);        return new LoadData<>(url, new HttpUrlFetcher(url, timeout));    }    @Override    public boolean handles(GlideUrl model) {        return true;    }    public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {        private final ModelCache<GlideUrl, GlideUrl> modelCache = new ModelCache<>(500);        @Override        public ModelLoader<GlideUrl, InputStream> build(MultiModelLoaderFactory multiFactory) {            return new HttpGlideUrlLoader(modelCache);        }        @Override        public void teardown() {            // Do nothing.        }    }}

可以看到,buildLoadData(GlideUrl, int, int, Options)的返回值为new LoadData<>(url, new HttpUrlFetcher(url, timeout)),其中,url就是一个用访问的图片地址转换成的GlideUrl对象

package com.bumptech.glide.load.model;...public interface ModelLoader<Model, Data> {    class LoadData<Data> {        public final Key sourceKey;        public final List<Key> alternateKeys;        public final DataFetcher<Data> fetcher;        public LoadData(Key sourceKey, DataFetcher<Data> fetcher) {            this(sourceKey, Collections.<Key>emptyList(), fetcher);        }        public LoadData(Key sourceKey, List<Key> alternateKeys, DataFetcher<Data> fetcher) {            this.sourceKey = Preconditions.checkNotNull(sourceKey);            this.alternateKeys = Preconditions.checkNotNull(alternateKeys);            this.fetcher = Preconditions.checkNotNull(fetcher);        }    }    ...}

也就是说,该LoadData对象的sourceKey为一个GlidUrl对象,而该GlidUrl对象是有图片来源地址转换而来的,看下GlideUrl源码

package com.bumptech.glide.load.model;...public class GlideUrl implements Key {    private static final String ALLOWED_URI_CHARS = "@#&=*+-_.,:!?()/~'%";    private final Headers headers;    @Nullable    private final URL url;    @Nullable    private final String stringUrl;    @Nullable    private String safeStringUrl;    @Nullable    private URL safeUrl;    @Nullable    private volatile byte[] cacheKeyBytes;    private int hashCode;    public GlideUrl(URL url) {        this(url, Headers.DEFAULT);    }    public GlideUrl(String url) {        this(url, Headers.DEFAULT);    }    public GlideUrl(URL url, Headers headers) {        this.url = Preconditions.checkNotNull(url);        stringUrl = null;        this.headers = Preconditions.checkNotNull(headers);    }    public GlideUrl(String url, Headers headers) {        this.url = null;        this.stringUrl = Preconditions.checkNotEmpty(url);        this.headers = Preconditions.checkNotNull(headers);    }    public URL toURL() throws MalformedURLException {        return getSafeUrl();    }    private URL getSafeUrl() throws MalformedURLException {        if (safeUrl == null) {            safeUrl = new URL(getSafeStringUrl());        }        return safeUrl;    }    public String toStringUrl() {        return getSafeStringUrl();    }    private String getSafeStringUrl() {        if (TextUtils.isEmpty(safeStringUrl)) {            String unsafeStringUrl = stringUrl;            if (TextUtils.isEmpty(unsafeStringUrl)) {                unsafeStringUrl = url.toString();            }            safeStringUrl = Uri.encode(unsafeStringUrl, ALLOWED_URI_CHARS);        }        return safeStringUrl;    }    public Map<String, String> getHeaders() {        return headers.getHeaders();    }    public String getCacheKey() {        return stringUrl != null ? stringUrl : url.toString();    }    @Override    public String toString() {        return getCacheKey();    }    @Override    public void updateDiskCacheKey(MessageDigest messageDigest) {        messageDigest.update(getCacheKeyBytes());    }    private byte[] getCacheKeyBytes() {        if (cacheKeyBytes == null) {            cacheKeyBytes = getCacheKey().getBytes(CHARSET);        }        return cacheKeyBytes;    }    @Override    public boolean equals(Object o) {        if (o instanceof GlideUrl) {            GlideUrl other = (GlideUrl) o;            return getCacheKey().equals(other.getCacheKey())                    && headers.equals(other.headers);        }        return false;    }    @Override    public int hashCode() {        if (hashCode == 0) {            hashCode = getCacheKey().hashCode();            hashCode = 31 * hashCode + headers.hashCode();        }        return hashCode;    }}
0 0