Android网络请求6--解析Glide缓存机制

1. 简介

Glide缓存分为两部分,分别为内存缓存和硬盘缓存。其中内存缓存的主要作用是防止应用重复地将图片数据读取到内存中,而硬盘缓存的主要作用是防止应用重复从网络或其他地方重复下载和读取数据。

内存缓存和硬盘缓存的配合才实现了Glide极佳的图片缓存效果。

2. 缓存Key

大家都知道,如果想缓存一个东西的话,必然会有对应的缓存key。那么Glide的缓存key在哪呢?

首先我们来看下Engine.load()方法:

public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
        DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
        Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
    // 判断是否为主线程
    Util.assertMainThread();
    // 获取当前时间
    long startTime = LogTime.getLogTime();

    // 生成key,包括id、width、height、signature以及decoder等参数
    final String id = fetcher.getId();
    EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
            loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
            transcoder, loadProvider.getSourceEncoder());
    
    // -----------读取内存缓存-----------
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
        cb.onResourceReady(cached);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Loaded resource from cache", startTime, key);
        }
        return null;
    }

    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
        cb.onResourceReady(active);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Loaded resource from active resources", startTime, key);
        }
        return null;
    }

    EngineJob current = jobs.get(key);
    if (current != null) {
        current.addCallback(cb);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Added to existing load", startTime, key);
        }
        return new LoadStatus(cb, current);
    }

    // -----------runnable中会先读取磁盘缓存-----------
    EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
    DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
            transcoder, diskCacheProvider, diskCacheStrategy, priority);
    EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
    jobs.put(key, engineJob);
    engineJob.addCallback(cb);
    engineJob.start(runnable);

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
}

我们现在需要关注的核心就是10-13行的代码。可以看到,他在10行调用了fetcher.getId()方法获得了一个id字符串,这个字符串也是我们要加载图片的唯一标识,比如说我们要从网络读取,那图片的Url就是他的id。

接下来,通过id、signature、width、height等一些列参数传入EngineKeyFactory的buildKey()方法当中,从而构建出了一个EngineKey对象。这个对象就是Glide的缓存key了。

3. 内存缓存

首先我们来看下Glide如何使用图片缓存。

3.1 用法

内存缓存Glide是默认开启的。

也就是说,当我们使用Glide加载一张图片之后,这张图片就会被缓存到内存当中,只要她还没从内存中被清除,下次使用Glide加载这张图片都会直接从内存中读取。这样无疑可以大幅度提升图片的加载效率。

那么既然是默认开启的,怎样才可以关闭他呢?

Glide对此也提供了方法:

Glide.with(this)
     .load(url)
     .skipMemoryCache(true)
     .into(imageView);

通过skipMemoryCache() API 就可以关闭它。

3.2 源码

说起缓存,大家一定第一反应就是LRUCache。没错,内存缓存就是通过LRUCache实现的,但是他除了LRUCache之外,还有一种弱引用缓存。那就让我们通过源码来分析下:

还记得我们在讲Glide请求源码load()的时候,分析到在loadGeneric()方法中会调用Glide.buildStreamModelLoader()方法来回去一个ModelLoader对象,我们现在来看下他的源码:

public static <T> ModelLoader<T, InputStream> buildStreamModelLoader(Class<T> modelClass, Context context) {
    return buildModelLoader(modelClass, InputStream.class, context);
}

可以看到这个方法直接调用了buildModelLoader()方法,我们再来看看这个方法:

public static <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass,
        Context context) {
     if (modelClass == null) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "Unable to load null model, setting placeholder only");
        }
        return null;
    }
    return Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass);
}

核心代码就是return那一句,可以看到他先调用了一个Glide.get()方法,而这个方法就是关键:

public static Glide get(Context context) {
    // 懒汉单例模式
    if (glide == null) {
        synchronized (Glide.class) {
            if (glide == null) {
                // 构造对象之前的一些配置
                Context applicationContext = context.getApplicationContext();
                List<GlideModule> modules = new ManifestParser(applicationContext).parse();
                GlideBuilder builder = new GlideBuilder(applicationContext);
                for (GlideModule module : modules) {
                    module.applyOptions(applicationContext, builder);
                }
                // 创建Glide对象
                glide = builder.createGlide();
                for (GlideModule module : modules) {
                    module.registerComponents(applicationContext, glide);
                }
            }
        }
    }
    return glide;
}

这个方法基本上就是一个单例模式获取对象的常规写法。可以直接看14行,glide的构造方式就是调用builder.createGlide()方法,我们再来看下这个方法:

Glide createGlide() {
    if (sourceService == null) {
        final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
        sourceService = new FifoPriorityThreadPoolExecutor(cores);
    }
    if (diskCacheService == null) {
        diskCacheService = new FifoPriorityThreadPoolExecutor(1);
    }

    MemorySizeCalculator calculator = new MemorySizeCalculator(context);
    // 创建BitmapPool
    if (bitmapPool == null) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            int size = calculator.getBitmapPoolSize();
            bitmapPool = new LruBitmapPool(size);
        } else {
            bitmapPool = new BitmapPoolAdapter();
        }
    }

    // 创建内存缓存
    if (memoryCache == null) {
        memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
    }

    // 创建硬盘缓存
    if (diskCacheFactory == null) {
        diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }

    // 创建engine
    if (engine == null) {
        engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService);
    }

    // 创建DecodeFormat
    if (decodeFormat == null) {
        decodeFormat = DecodeFormat.DEFAULT;
    }

    // 返回创建好的Glide对象
    return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
}

目前我们只需要关注内存缓存部分。第23行创建了一个LruResourceCache对象,并赋值给了memoryCache。这个就是Glide实现内存缓存所用的LruCache对象了。到这缓存的准备工作就做好了。

接下来我们继续回到Engine的load()方法:

public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
        DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
        Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
    
    // ... 省略部分代码
    
    // -----------读取内存缓存-----------
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
        cb.onResourceReady(cached);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Loaded resource from cache", startTime, key);
        }
        return null;
    }

    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
        cb.onResourceReady(active);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Loaded resource from active resources", startTime, key);
        }
        return null;
    }

    EngineJob current = jobs.get(key);
    if (current != null) {
        current.addCallback(cb);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Added to existing load", startTime, key);
        }
        return new LoadStatus(cb, current);
    }

    // -----------runnable中会先读取磁盘缓存-----------
    EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
    DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
            transcoder, diskCacheProvider, diskCacheStrategy, priority);
    EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
    jobs.put(key, engineJob);
    engineJob.addCallback(cb);
    engineJob.start(runnable);

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
}

在第8行调用了loadFromCache()方法来获取缓存图片,并通过cb.onResourceReady()方法进行回调;如果没有获取到,就会在17行调用loadFromActiveResources()来获取缓存图片。只有在两个方法都获取不到的时候才会继续向下执行,从而开启线程加载图片。

也就是说,load()方法会通过两个方式来获取内存缓存:loadFromCache()loadFromActiveResources()。这两个方法一个是LruCache,一个是弱引用。

public class Engine implements EngineJobListener,
        MemoryCache.ResourceRemovedListener,
        EngineResource.ResourceListener {
    
    // ...
    
    private final MemoryCache cache;
    private final Map<Key, WeakReference<EngineResource<?>>> activeResources;
    
    // ...
    
    // 从activeResources中取出图片
    private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
        if (!isMemoryCacheable) {
            return null;
        }

        EngineResource<?> active = null;
        WeakReference<EngineResource<?>> activeRef = activeResources.get(key);
        if (activeRef != null) {
            active = activeRef.get();
            if (active != null) {
                active.acquire();
            } else {
                activeResources.remove(key);
            }
        }

        return active;
    }

    private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
        // 判断内存缓存是否被禁用
        if (!isMemoryCacheable) {
            return null;
        }

        // 通过key调用getEngineResourceFromCache方法来获取缓存,见下面
        EngineResource<?> cached = getEngineResourceFromCache(key);
        if (cached != null) {
            cached.acquire();
            // 又存入activeResources中
            // activeResources就是一个弱引用的HashMap,用来缓存正在使用的图片
            activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
        }
        return cached;
    }
    
    @SuppressWarnings("unchecked")
    private EngineResource<?> getEngineResourceFromCache(Key key) {
        // 根据key找到对应缓存并取出移除
        Resource<?> cached = cache.remove(key);

        final EngineResource result;
        // 根据取出的cached来构建result
        if (cached == null) {
            result = null;
        } else if (cached instanceof EngineResource) {
            // Save an object allocation if we've cached an EngineResource (the typical case).
            result = (EngineResource) cached;
        } else {
            result = new EngineResource(cached, true /*isCacheable*/);
        }
        // 将result返回
        return result;
    }
    
    // ...
}

缓存步骤应该先从loadFromCache()方法开启,他首先调用getEngineResourceFromCache()方法获取缓存。这个方法是根据传入的key然后取出缓存,接着判断如果缓存是EngineResource的对象的话就将cached造型成EngineResource的对象并返回,否则的话直接根据cached调用EngineResource的构造方法返回result。

现在我们回到loadFromCache()方法,我们得到缓存后,在把它存入activeResources。activeResources就是弱引用的HashMap。由此可知,loadFromActiveResources()方法就是从这个activeResources中取值。由于它是弱引用缓存,所以他可以保护这些图片不会被LruCache算法回收掉。

所以大致流程就是先从内存中读取缓存,读取出来了就把它从内存中移除并存入ActiveResources弱引用缓存,接着直接从弱引用缓存中取。如果内存中读取不到的话,就开启线程从网络中获取。

但是,回想我们之前的研究过程,发现我们分析了缓存是怎么被取出来的,但是没有说缓存是什么时候被存进去的。

还记得我们之前说过,在图片加载完成之后,会在EngineJob中通过Handler发送一条消息将执行逻辑切回到主线程中,从而执行handleResultOnMainThread()方法。现在我们来重新看下这个方法:

private void handleResultOnMainThread() {
    // 是否取消
    if (isCancelled) {
        resource.recycle();
        return;
    } else if (cbs.isEmpty()) {
        throw new IllegalStateException("Received a resource without any callbacks to notify");
    }
    
    // 构建EngineResource对象
    engineResource = engineResourceFactory.build(resource, isCacheable);
    hasResource = true;

    // Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it
    // synchronously released by one of the callbacks.
    engineResource.acquire();
    // 回调
    listener.onEngineJobComplete(key, engineResource);

    for (ResourceCallback cb : cbs) {
        if (!isInIgnoredCallbacks(cb)) {
            engineResource.acquire();
            cb.onResourceReady(engineResource);
        }
    }
    // Our request is complete, so we can release the resource.
    engineResource.release();
}

在第11行中,通过engineResourceFactory的build()方法构建出EngineResource对象,并在第18行通过回调返回到了Engine的onEngineJobComplete()方法中去:

@Override
public void onEngineJobComplete(Key key, EngineResource<?> resource) {
    Util.assertMainThread();
    // A null resource indicates that the load failed, usually due to an exception.
    if (resource != null) {
        resource.setResourceListener(key, this);

        if (resource.isCacheable()) {
            // 存入ActiveResources
            activeResources.put(key, new ResourceWeakReference(key, resource, getReferenceQueue()));
        }
    }
    // TODO: should this check that the engine job is still current?
    jobs.remove(key);
}

可以看到在这个方法中,第10行,就被put进了activeResources中。

这块我们加载到的图片就存入了弱引用缓存中。

但是我们什么时候存入LruCache中的呢?

回到刚刚的handleResultOnMainThread()方法。16行和22行分别调用了EngineResource的acquire()方法,在第27行调用了他的release()方法。

那我们来看下这两个方法:

class EngineResource<Z> implements Resource<Z> {

    private int acquired;

    void acquire() {
        if (isRecycled) {
            throw new IllegalStateException("Cannot acquire a recycled resource");
        }
        if (!Looper.getMainLooper().equals(Looper.myLooper())) {
            throw new IllegalThreadStateException("Must call acquire on the main thread");
        }
        // 核心就是让acquired这个变量++
        ++acquired;
    }
    
        void release() {
        if (acquired <= 0) {
            throw new IllegalStateException("Cannot release a recycled or not yet acquired resource");
        }
        if (!Looper.getMainLooper().equals(Looper.myLooper())) {
            throw new IllegalThreadStateException("Must call release on the main thread");
        }
        // 同样核心就是让acquired这个变量--
        if (--acquired == 0) {
            // 回调,见下面
            listener.onResourceReleased(key, this);
        }
    }
}

/**
 * Engine.onResourceReleased()
 */
@Override
public void onResourceReleased(Key cacheKey, EngineResource resource) {
    Util.assertMainThread();
    // 根据key从activeResources中移除
    activeResources.remove(cacheKey);
    // 存入LruCache中
    if (resource.isCacheable()) {
        cache.put(cacheKey, resource);
    } else {
        resourceRecycler.recycle(resource);
    }
}

可以看到,Engine维护了一个对象,叫做acquired,然后acquire()方法会让这个变量加1,release()方法会让它减1。

如果acquired变量大于1,就证明图片正在被使用,那么就放到activeResources当中去。经过release()之后,acquired减1,如果减成0了,那就说明当前图片没有被正在使用,那就可以调用onResourceReleased()方法来释放资源。

onResourceReleased()方法中,会将缓存先从activeResources中移除,然后再将它put到LRUResourceCache中。这样也就实现了正在使用中的图片使用弱引用来进行缓存,不在使用中的图片使用LruCache来进行缓存的功能。

4. 硬盘缓存

一样的,我们首先来看下他的用法。

4.1 用法

Glide.with(this)
     .load(url)
     .diskCacheStrategy(DiskCacheStrategy.NONE)
     .into(imageView);

而这个diskCacheStrategy()方法基本上就是Glide硬盘缓存的一切,他可以接收四种参数:

  • DiskCacheStrategy.NONE: 表示不缓存任何内容。
  • DiskCacheStrategy.SOURCE: 表示只缓存原始图片。
  • DiskCacheStrategy.RESULT: 表示只缓存转换过后的图片(默认选项)。
  • DiskCacheStrategy.ALL : 表示既缓存原始图片,也缓存转换过后的图片。

4.2 源码

首先让我们回到EngineRunnable的run()方法。如果对Glide加载图片有印象的同学会记得这个方法,这个方法就是在Glide开启线程加载图片后执行的。然后run方法里面又会有一个decode()方法:

private Resource<?> decode() throws Exception {
    if (isDecodingFromCache()) {
        return decodeFromCache();
    } else {
        return decodeFromSource();
    }
}

到这时会分为两种情况,一种是调用decodeFromCache()方法从硬盘缓存中读取图片,另一种是调用decodeFromSource()来读取原始图片,正常情况下会优先从缓存中读取文件,如果缓存中读不到再去读取原始文件。那我们先来看下decodeFromCache()的源码:

private Resource<?> decodeFromCache() throws Exception {
    Resource<?> result = null;
    try {
        // 调用此方法获取转换后的缓存
        result = decodeJob.decodeResultFromCache();
    } catch (Exception e) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "Exception decoding result from cache: " + e);
        }
    }

    // 调用此方法获取原始图片缓存
    if (result == null) {
        result = decodeJob.decodeSourceFromCache();
    }
    return result;
}

这里调用了两个获取缓存的方法,一个是decodeResultFromCache(),另一个是decodeSourceFromCache()方法。decodeResultFromCache()是获取原始图片经过Glide转换后的图片,而decodeSourceFromCache()则是获取原始图片。

那我们来看下这两个方法:

public Resource<Z> decodeResultFromCache() throws Exception {
    if (!diskCacheStrategy.cacheResult()) {
        return null;
    }

    long startTime = LogTime.getLogTime();
    Resource<T> transformed = loadFromCache(resultKey);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Decoded transformed from cache", startTime);
    }
    startTime = LogTime.getLogTime();
    Resource<Z> result = transcode(transformed);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Transcoded transformed from cache", startTime);
    }
    return result;
}
    
public Resource<Z> decodeSourceFromCache() throws Exception {
    if (!diskCacheStrategy.cacheSource()) {
        return null;
    }

    long startTime = LogTime.getLogTime();
    Resource<T> decoded = loadFromCache(resultKey.getOriginalKey());
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Decoded source from cache", startTime);
    }
    return transformEncodeAndTranscode(decoded);
}

可以看到他两都是调用了loadFromCache()方法去读取缓存,但是如果是decodeResultFromCache()就直接将数据返回,如果是decodeSourceFromCache(),则调用transformEncodeAndTranscode()方法将数据转换一下在返回。

而且还一点就是他两调用loadFromCache()的参数也不一样,decodeResultFromCache()方法是直接传入的key,但是decodeSourceFromCache()传入的是key.getOriginalKey()

public Key getOriginalKey() {
    if (originalKey == null) {
        originalKey = new OriginalKey(id, signature);
    }
    return originalKey;
}

可以看到,这里其实就是忽略了绝大部分的参数,只使用了id和signature这两个参数来构成缓存Key。而signature参数绝大多数情况下都是用不到的,因此基本上可以说就是由id(也就是图片url)来决定的Original缓存Key。

这块弄懂了我们就直接来看下loadFromCache()的源码吧:

private Resource<T> loadFromCache(Key key) throws IOException {
    File cacheFile = diskCacheProvider.getDiskCache().get(key);
    if (cacheFile == null) {
        return null;
    }

    Resource<T> result = null;
    try {
        result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
    } finally {
        if (result == null) {
            diskCacheProvider.getDiskCache().delete(key);
        }
    }
    return result;
}

先调用diskCacheProvidergetDiskCache()方法获取到Glide的DiskLruCache工具类的实例,然后调用它的get()方法得到缓存文件。,如果不为空,就转码转成result并返回。

这样就是整个磁盘缓存读取的流程。那他是在哪儿写入缓存的呢?

我们来看下decodeFromSource这个方法:

public Resource<Z> decodeFromSource() throws Exception {
    // 解析图片
    Resource<T> decoded = decodeSource();
    // 对图片进行转换和转码
    return transformEncodeAndTranscode(decoded);
}

我们先来看下decodeSource()这个方法:

private Resource<T> decodeSource() throws Exception {
    Resource<T> decoded = null;
    try {
        long startTime = LogTime.getLogTime();
        // 读取到数据
        final A data = fetcher.loadData(priority);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Fetched data", startTime);
        }
        if (isCancelled) {
            return null;
        }
        // 调用decodeFromSourceData进行解码
        decoded = decodeFromSourceData(data);
    } finally {
        fetcher.cleanup();
    }
    return decoded;
}

private Resource<T> decodeFromSourceData(A data) throws IOException {
    final Resource<T> decoded;
    //  判断是否允许缓存原始图片
    if (diskCacheStrategy.cacheSource()) {
        // 缓存原始图片
        decoded = cacheAndDecodeSourceData(data);
    } else {
        long startTime = LogTime.getLogTime();
        // 进行转码
        decoded = loadProvider.getSourceDecoder().decode(data, width, height);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Decoded from source", startTime);
        }
    }
    return decoded;
}

private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
    long startTime = LogTime.getLogTime();
    SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data);
    diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Wrote source to cache", startTime);
    }

    startTime = LogTime.getLogTime();
    Resource<T> result = loadFromCache(resultKey.getOriginalKey());
    if (Log.isLoggable(TAG, Log.VERBOSE) && result != null) {
        logWithTimeAndKey("Decoded source from cache", startTime);
    }
    return result;
}

首先现在第6行调用fetcher.loadData()来获取图片数据,然后再调用decodeFromSourceData()来进行解码。

decodeFromSourceData()这个方法进去后,先判断是否允许缓存图片,如果允许,就调用cacheAndDecodeSourceData()方法。

cacheAndDecodeSourceData()这个方法同样是通过getDiskCache()方法来获取DiskLruCache实例,接着调用它的put()方法就可以写入硬盘缓存了。

这块就是原始图片的缓存写入。接下来我们再来看下transformEncodeAndTranscode()这个方法是如何将转码后的图片写入缓存的:

private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
    long startTime = LogTime.getLogTime();
    // 对图片进行转换
    Resource<T> transformed = transform(decoded);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Transformed resource from source", startTime);
    }

    // 调用此方法将转换后的结果存入磁盘
    writeTransformedToCache(transformed);

    startTime = LogTime.getLogTime();
    Resource<Z> result = transcode(transformed);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Transcoded transformed from source", startTime);
    }
    return result;
}

private void writeTransformedToCache(Resource<T> transformed) {
    if (transformed == null || !diskCacheStrategy.cacheResult()) {
        return;
    }
    long startTime = LogTime.getLogTime();
    SourceWriter<Resource<T>> writer = new SourceWriter<Resource<T>>(loadProvider.getEncoder(), transformed);
    // 存入LruCache
    diskCacheProvider.getDiskCache().put(resultKey, writer);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Wrote transformed from source to cache", startTime);
    }
}

这里的逻辑就更加简单明了了。先是在第4行调用transform()方法来对图片进行转换,然后在writeTransformedToCache()方法中将转换过后的图片写入到硬盘缓存中,调用的同样是DiskLruCache实例的put()方法,不过这里用的缓存Key是resultKey。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章