关于上一篇大概走了一下Glide加载的基本流程,篇幅超长,没有耐心的人很难看完,所以我觉得这一片篇改变记录方案,走流程的事情就给有兴趣的人们吧!
简单了解缓存KEY
说到Glide的缓存那就要说缓存key,它的key是由十个参数来决定的,但是也就是为了是加载的图片唯一性罢了,看看源码吧:
EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
transcoder, loadProvider.getSourceEncoder());
Glide 的双缓存原理:
磁盘缓存:
一般的图片缓存指的就是磁盘缓存,把网络上的图片缓存到本地,这样就不需要每次都从网络加载,既提高了加载速度,又为用户节省了流量。
Glide在默认情况下是开启磁盘缓存的,而且提供了丰富的API来让开发者自己配置和管理磁盘缓存。
修改缓存位置和缓存大小:
我们要继承一个GlideModule的接口,然后实现他的两个方法如下:
public class DiskCacheMoudle implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
builder.setDiskCache(new InternalCacheDiskCacheFactory(context, "glide_cache", 100 * 1024 * 1024));
//builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, "glide_cache", 100 * 1024 * 1024));
}
@Override
public void registerComponents(Context context, Glide glide) {
}
}
可以看到我们new 出了一个InternalCacheDiskCacheFactory实例,那么我们可以去看看这个对象是怎么实现的
public final class InternalCacheDiskCacheFactory extends DiskLruCacheFactory {
public InternalCacheDiskCacheFactory(Context context) {
this(context, DiskCache.Factory.DEFAULT_DISK_CACHE_DIR, DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE);
}
public InternalCacheDiskCacheFactory(Context context, int diskCacheSize) {
this(context, DiskCache.Factory.DEFAULT_DISK_CACHE_DIR, diskCacheSize);
}
public InternalCacheDiskCacheFactory(final Context context, final String diskCacheName, int diskCacheSize) {
super(new CacheDirectoryGetter() {
@Override
public File getCacheDirectory() {
File cacheDirectory = context.getCacheDir();
if (cacheDirectory == null) {
return null;
}
if (diskCacheName != null) {
return new File(cacheDirectory, diskCacheName);
}
return cacheDirectory;
}
}, diskCacheSize);
}
}
很简单,就是获取到应用的内部存储,如果不想存储在内存,就可以使用与之对应的ExternalCacheDiskCacheFactory类,我们在这两个类中可以看到有一个静态的DiskCache.Factory方法,跟进去可以看到Glide默认的缓存大小是250M;缓存的文件名是:”image_manager_disk_cache”,如果不想缓存在内部或者外部,那么你就可以自己设置一个目录方法如下:
builder.setDiskCache(
new DiskLruCacheFactory(new DiskLruCacheFactory.CacheDirectoryGetter() {
@Override
public File getCacheDirectory() {
return getMyCacheLocationBlockingIO();
}
}), 100 * 1024 * 1024);
通过网上查询,getMyCacheLocationBlockingIO()方法返回的文件不能为空,并且只能是一个建立了的文件夹,不能是文件;(所以感觉这个用处好像不大);
磁盘缓存策略
先普及一下Glide中的四种缓存策略:
- DiskCacheStrategy.NONE 不缓存文件
- DiskCacheStrategy.SOURCE 只缓存原图
- DiskCacheStrategy.RESULT 只缓存最终加载的图(默认的缓存策略)
- DiskCacheStrategy.ALL 同时缓存原图和结果图
什么是原图?什么是结果图?
假如你要加载的图片分辨率为1000x1000,但是最终显示该图片的ImageView大小只有500x500,那么Glide就会只缓存500x500的小图。这也是在从磁盘缓存中加载图片时Glide比Picasso快的原因。
如果你想改变缓存策略只要:(我随机选择的)
Glide.diskCacheStrategy(DiskCacheStrategy.ALL)
磁盘缓存算法
在Glide中磁盘缓存默认使用的是LRU(Least Recently Used)算法。如果你想使用其他的缓存算法,就只能通过实现DiskCache接口来完成了。
内存缓存:
- 由于Glide 默认是开启内存缓存的,(skipMemoryCache(true)关闭)。
- 缓存的Glide里面使用内存缓存是使用了一个叫BitmapPool的对象,从名字就可以看出这是一个bitmap池,里面有几个可以复用的对象。
- 使用了LruCache算法。
- 使用了弱引用机制(代码如下)
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
private final MemoryCache cache;
private final Map<Key, WeakReference<EngineResource<?>>> activeResources;
、
、
、
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
}
return cached;
}
private EngineResource<?> getEngineResourceFromCache(Key key) {
Resource<?> cached = cache.remove(key);
final EngineResource result;
if (cached == null) {
result = null;
} else if (cached instanceof EngineResource) {
result = (EngineResource) cached;
} else {
result = new EngineResource(cached, true /*isCacheable*/);
}
return result;
}
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;
}
、
、
}
当从LruResourceCache中获取到缓存图片之后会将它从缓存中移除,然后将这个缓存图片存储到activeResources当中。activeResources就是一个弱引用的HashMap,用来缓存正在使用中的图片。
内存缓存并不是不可修改的,我们可以通过修改Bitmappool的大小来修改:
builder.setMemoryCache(new LruResourceCache(yourSizeInBytes));//修改内存
builder.setBitmapPool(new LruBitmapPool(sizeInBytes));//修改缓存池
默认的内存缓存和BitmapPool的大小由MemorySizeCalculator根据当前设备的屏幕大小和可用内存计算得到。同时Glide还支持动态的缓存大小调整,在存在大量图片的Activity/Fragment中,开发者可以通过setMemoryCategory方法来提高Glide的内存缓存大小,从而加快图片的加载速度。
同理,磁盘缓存策略有四种策略,内存同样也有三中策略:
MemoryCategory有3个值可供选择:
- MemoryCategory.HIGH(初始缓存大小的1.5倍)
- MemoryCategory.NORMAL(初始缓存大小的1倍)
- MemoryCategory.LOW(初始缓存大小的0.5倍)
总结
看这个样子两级缓存也是参照了计算机操作系统中的三级缓存思想了,不得不说这是一个天才级的想法,以后可以多多使用,有兴趣的人可以自己谢谢两级缓存加深下理解,当然也可以参照下我当时联系的时候写的那个MyImageloader。
GitHub连接: https://github.com/wangjiapu/MyImageloager