概述
一、磁盘缓存
其实磁盘缓存的原理没什么好说的?为什么这么说呢?因为Glide磁盘缓存的实现使用的也是JakeWharton大神的DisLruCache,所以呢,我们也是直接拿过来用即可,直接把这三个文件直接Copy即可。下面我们来说一下磁盘缓存怎么去使用:
首先我们先写一个磁盘缓存用到的接口类DiskCache
public interface DiskCache {
interface Writer {
boolean write(File file);
}
File get(Key key);
void put(Key key, Writer writer);
void delete(Key key);
void clear();
}
get,put,delete,clear这四个方法看名字就知道具体的作用,至于Writer和它的write方法,主要就是对图片进行解码,用到的时候我们具体说。下面是DiskCache的实现类DiskLruCacheWrapper:
public class DiskLruCacheWrapper implements DiskCache {
final static int DEFAULT_DISK_CACHE_SIZE = 250 * 1024 * 1024;
final static String DEFAULT_DISK_CACHE_DIR = "image_manager_disk_cache";
private MessageDigest MD;
private DiskLruCache diskLruCache;
public DiskLruCacheWrapper(Context context) {
this(new File(context.getCacheDir(), DEFAULT_DISK_CACHE_DIR), DEFAULT_DISK_CACHE_SIZE);
}
protected DiskLruCacheWrapper(File directory, long maxSize) {
try {
MD = MessageDigest.getInstance("SHA-256");
//打开一个缓存目录,如果没有则首先创建它,
// directory:指定数据缓存地址
// appVersion:APP版本号,当版本号改变时,缓存数据会被清除
// valueCount:同一个key可以对应多少文件
// maxSize:最大可以缓存的数据量
diskLruCache = DiskLruCache.open(directory, 1, 1, maxSize);
} catch (Exception e) {
e.printStackTrace();
}
}
public String getKey(Key key) {
key.updateDiskCacheKey(MD);
return new String(Utils.sha256BytesToHex(MD.digest()));
}
@Nullable
@Override
public File get(Key key) {
String k = getKey(key);
File result = null;
try {
DiskLruCache.Value value = diskLruCache.get(k);
if (value != null) {
result = value.getFile(0);
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
/**
* 加入磁盘缓存
* @param key
* @param writer
*/
@Override
public void put(Key key, Writer writer) {
String k = getKey(key);
try {
DiskLruCache.Value current = diskLruCache.get(k);
if (current != null) {
return;
}
DiskLruCache.Editor editor = diskLruCache.edit(k);
try {
File file = editor.getFile(0);
if (writer.write(file)) {
editor.commit();
}
} finally {
editor.abortUnlessCommitted();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void delete(Key key) {
String k = getKey(key);
try {
diskLruCache.remove(k);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void clear() {
try {
diskLruCache.delete();
} catch (IOException e) {
e.printStackTrace();
}
}
}
简单的说一下:
构造方法中主要做了一些初始化的工作,包括:计算Hash的算法名称(我这里用的是SHA-256),初始化磁盘缓存的位置,版本,大小等。其他的四个方法就是一些具体的操作,可以自己看看,都不难,如果有问题可以给我留言。
二、加载器
我们先看一张架构图,然后我们再去理解这个加载器的流程
上面的架构图并不是真正Glide的架构模式,这个是我们要写的阉割版Glide的架构,不过流程基本没变。
这里的处理数据的模型只有4个,但是真正的Glide的数据处理模型有好几十个,我这里只拿出来几个比较常用的来说。
我们一步一步来:
第一步:Glide在初始化的时候,都会把相应的数据处理模型注册到ModelLoaderRegister中,模型中的Model指的是图片资源的类型,Data指的是加载文件后的输出类型,我这里一律以InputStream的格式进行输出。Factory主要就是创建相应ModelLoader来进行数据的加载(真正进行数据加载的其实是LoadData的fetcher,这个我们稍后说)。然后将这三个元素封装在一个Entry类中,加入到ModelLoaderRegister中。
第二步:当图片资源加入到Glide时,系统会根据资源的类型,在ModelLoaderRegister中查找,哪种数据模型可以处理这个图片资源。当然查找的结果可能是多种,也可能是一种,所以我们使用List来装。找到符合的数据模型后,Factory就会调用build来创建一个ModelLoader对象。比如图片资源File类型时,找到的Factory是FileLoader.Factory,但它在build的时候,其实是ModelLoaderRegister根据Model为Uri,Data为InputStream进行build相应的ModelLoader(估计到这里,好多同学就懵了。怎么又回去了?FileLoader感觉什么也没做呢?是的,其实FileLoader更像是中转站)。ModelLoaderRegister在build的时候,又会出现上面的问题,ModelLoader可能有一个,也有可能是多个,怎么办?我们还要保证返回值是同一类型。有的同学可能会说,可以使用List。我认为这样设计没有问题。ModelLoader中都有一个buildData,方法的参数就是图片资源,我们可以在这里对List进行遍历,拿出每个ModelLoader来进行handle,看看能不能处理图片资源。但是这就要每个ModelLoader都要在这个方法中写循环的重复代码,很冗余。所以Glide就创建了一个叫做MultiModelLoader的类,它也是ModelLoader,在这个类里面有一个ModelLoader的集合。所以ModelLoaderRegister在build的时候,如果是一个则返回相应的ModelLoader;如果是多个,则统一放在MultiModelLoader的集合里,判断逻辑统一在MultiModelLoader的buildData方法来做。
第三步:如果图片是网络图片,那么ModelLoader最后会被定位为HttpUriLoader,通过buildData,找对应的HttpUriFetcher进行图片的获取;如果图片是本地图片,那么ModelLoader最后会被定位为FileUriLoader,通过buildData,找到对应的Fetcher为FileUriFetcher,然后进行资源的获取。
加载器这部分很重要,但是的确很难理解,我们需要反复的去看源码才可以,不是我几句话就能说得清楚的,我这里仅仅是抛砖引玉吧。代码我就不贴了,类实在是不少,我会把这部分的代码提供出来供大家研究。代码
欢迎大家提问和纠错!
最后
以上就是魁梧哈密瓜为你收集整理的Glide框架解析---磁盘缓存与加载器(二)一、磁盘缓存二、加载器的全部内容,希望文章能够帮你解决Glide框架解析---磁盘缓存与加载器(二)一、磁盘缓存二、加载器所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复