啥是三级缓存
三级缓存指的是:
- 网络缓存(顺序优先级最低)
- 本地缓存 (优先级次之)
- 内存缓存(优先级最高)
为啥使用三级缓存
我们的App 经常会需要进行网络交互,通过网络获取图片是非常正常的事情。如果每次启动的时候都从网络拉取图片的话,这会消耗很多流量。对于用户来讲,流量就意味着电话费,一个很耗流量的应用肯定会多花套餐钱,这样用户数量肯定要受到影响。
特别是当我们需要重复浏览加载一些图片时,如果每一次浏览都通过网络来获取加载,流量的浪费可想而知有多大。所以才提出三级缓存策略,通过网络、本地、内存三级缓存图片,来减少不必要的网络交互,避免浪费流量。
三级缓存基本原理
首次加载 App 时,通过网络来获取图片,然后我们将图片保存至本地SD卡和内存中
之后运行 App 时,优先访问内存中的图片缓存,若内存中没有,再加载本地SD卡中的图片,若本地SD卡中也没有就从网络中加载。
如何使用三级缓存
内存缓存
Lru(Least rencently used) :近期最少使用算法。LruCache和DisLruCache两个类,分别用于内存和硬盘缓存。核心思想是当缓存空间满了之后,会删除最近最少使用的缓存。
LruCache类使用
LruCache的原理是将缓存对象作为强引用,保存在LinkedHashMap中,当缓存满了之后,将对象从Map中移除,重新通过put方法添加新的缓存,get方法获取缓存。
int maxMemory = (int) (Runtime.getRuntime().totalMemory()/1024);
int cacheSize = maxMemory/8;
mMemoryCache = new LruCache(cacheSize){
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes()*value.getHeight()/1024;
} };
LruCache的核心思想就是维护一个缓存对象的队列,该队列由LinkedHashMap维护。一直没访问的对象放在队尾,最新访问的放在队首,当队列满了之后,从队尾开始淘汰,队首的最后淘汰。
本地缓存
由于DiskLruCache并不是由Google官方编写的,所以这个类并没有被包含在Android API当中,我们需要将这个类从网上下载下来,然后手动添加到项目当中。DiskLruCache的源码在Google Source上,地址如下:
android.googlesource.com/platform/libcore/+/jb-mr2-release/luni/src/main/java/libcore/io/DiskLruCache.java
下载好了源码之后,只需要在项目中新建一个io包,然后将DiskLruCache.java文件复制到这个包中即可。
DiskLruCache是不能new出实例的,如果我们要创建一个DiskLruCache的实例,则需要调用它的open()方法,接口如下所示:
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
open()方法接收四个参数,第一个参数指定的是数据的缓存地址,缓存地址通常都会存放在 /storage/Android/data/<你的包名>/cache, 这个路径下第二个参数指定当前应用程序的版本号,第三个参数指定同一个key可以对应多少个缓存文件,基本都是传1,第四个参数指定最多可以缓存多少字节的数据。
得到DiskLruCache的实例之后就可以对缓存的数据进行操作了,主要是写入、访问、移除等操作。
写入的操作是借助DiskLruCache.Editor这个类完成的。类似地,这个类也是不能new的,需要调用DiskLruCache的edit()方法来获取实例,接口如下所示:
public Editor edit(String key) throws IOException
可以看到,edit()方法接收一个参数key,这个key将会成为缓存文件的文件名,并且必须要和图片的URL是对应的。
String imageUrl = "https://xxx/xx/xx.jpg";
String key = hashKeyForDisk(imageUrl);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
有了DiskLruCache.Editor的实例之后,我们可以调用它的newOutputStream()方法来创建一个输出流,然后把它传入到downloadUrlToStream()中就能实现下载并写入缓存的功能了。注意newOutputStream()方法接收一个index参数,由于valueCount是1,所以index传0就可以了。在写入操作执行完之后,还需要执行commit()方法进行提交才能使写入生效,而调用abort()方法的话则表示放弃此次写入。
if (editor != null) {
OutputStream outputStream = editor.newOutputStream(0);
if (cacheToLocal(imageStream, outputStream)) {
editor.commit();
} else {
editor.abort();
}
}
mDiskLruCache.flush();
网络缓存
通过异步网络请求,获取网络资源
参考文章链接:https://blog.csdn.net/guolin_blog/article/details/28863651