Glide加载图片流程(Part Two)之缓存流程分析

承接上文,我们简单了解了Glide加载图片的流程,在这篇博文中,我们就来了解下Glide是如何缓存图片的。

上篇博文中我们知道,在初始化Glide对象时,GlideBuilder为我们配置了默认的缓存机制:

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);
        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);
        }

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

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

        return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
    }

代码清单2-1

通过上面的代码,我们可以了解到,Glide 使用了二级缓存机制。接下来我们就从图片的“从无到有”的过程来分析下具体的缓存流程。

一、缓存图片

上篇博文中,我们了解到,我们是在DecodeJobdecodeSource方法中拿到图片流资源。紧接着调用其decodeFromSourceData方法:

  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;
    }

方法中diskCacheStrategy是在GenericRequestBuilder初始化的,其值默认为DiskCacheStrategy.RESULT,即只缓存变换后的图片,而不直接保存原始资源到缓存。故上述方法中并没有保存原始的数据留到缓存中。

那么第一次写入缓存是什么时候呢?我们沿着代码继续往下看,待获取到decoded资源后,会在decodeFromSource中调用transformEncodeAndTranscode方法(不明白调用流程的可参考上篇博文):

  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);
        diskCacheProvider.getDiskCache().put(resultKey, writer);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Wrote transformed from source to cache", startTime);
        }
    }

transformEncodeAndTranscode方法中会将变换后的数据流(Resource<GifBitmapWrapper>对象)写入磁盘中,并将数据流转码为GlideBitmapDrawableResource

上篇博文我们知道,在拿到数据对象GlideBitmapDrawableResource后,经过一系列的方法调用,会走到EngineJobhandleResultOnMainThread方法中。在该方法中,会将我们原来的数据对象包装为EngineResource对象。这个对象使用了引用计数 方法对资源进行了控制。当有其他对象方法该资源时会增加计数,反之则减小引用次数。当引用次数减小至0时,则会回调ResourceListeneronResourceReleased方法。

同时,在handleResultOnMainThread方法中,会通过回调通知EngineEngineJob 已完成:

listener.onEngineJobComplete(key, engineResource);

现在我们来看看EngineonEngineJobComplete方法:

  @SuppressWarnings("unchecked")
    @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.put(key, new ResourceWeakReference(key, resource, getReferenceQueue()));
            }
        }
        // TODO: should this check that the engine job is still current?
        jobs.remove(key);
    }

在这个方法中为EngineResource设置了回调接口,并在activeResources添加了一个资源的若引用。

EngineResource的引用计数为0时会执行如下方法:

 @Override
    public void onResourceReleased(Key cacheKey, EngineResource resource) {
        Util.assertMainThread();
        activeResources.remove(cacheKey);
        if (resource.isCacheable()) {
            cache.put(cacheKey, resource);
        } else {
            resourceRecycler.recycle(resource);
        }
    }

该方法将资源从activeResources移除,并放到内存缓存cache中。

至此,图片的缓存流程已经分析结束,接下来我们看看缓存的使用。

二、读取缓存

缓存的读取主要发生在Engine中的load方法中,其读取的顺序依次为Memory cache、activeResources表、DiskCache 。相信通过前面的流程分析,读取缓存的流程就很容易了。

三、小结

Glide 使用的是二级缓存机制,并引入了引用计数 机制。朋友们可以在阅读源码的过程中慢慢体会其设计的精妙之处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值