博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android小知识-Android中的缓存策略(内存缓存和磁盘缓存)
阅读量:6177 次
发布时间:2019-06-21

本文共 4744 字,大约阅读时间需要 15 分钟。

本篇文章已授权微信公众号 顾林海 独家发布

通过缓存策略,我们不需要每次都从网上请求图片或从存储设备中加载图片,这样就极大地提高了图片的加载效率以及用户体验。目前比较常用的缓存策略是LruCache和DiskLruCache,其中LruCache被称为内存缓存,DiskLruCache被称为存储缓存。Lru是Least Recently Used的缩写,即最近最少使用算法,算法核心思想是:当缓存快满时,会淘汰近期最少使用的缓存目标。

缓存路径:内存->存储设备->网络

LruCache

LruCache是一个泛型类,它内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象,其提供了get和put方法来完成缓存的获取和添加操作,当缓存满时,LruCache会移除较早的缓存对象,然后再添加新的缓存对象。

LruCache是线程安全的。

  • 强引用、软引用和弱引用的区别:

  • 强引用:直接的对象引用。

  • 软引用:当一个对象只有软引用存在时,系统内存不足时此对象会被GC回收。

  • 弱引用:当一个对象只有弱引用存在时,此对象随时被GC回收。

LruCache初始化代码:

private LruCache
mMemoryCache;private void lruCache(){ //当进程可用的最大内存(KB) int maxMemory= (int) (Runtime.getRuntime().maxMemory()/1024); //LruCache缓存的总容量 int cacheSize=maxMemory/8; mMemoryCache=new LruCache
(cacheSize){ @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes()*value.getHeight()/1024; } };}复制代码

重写sizeOf方法,用来计算缓存对象的大小。

在一些特殊情况下,还需要重写LruCache的entryRemoved方法,LruCache移除旧缓存时会调用entryRemoved方法,可以在entryRemoved方法中做一些资源回收工作。

DiskLruCache

DiskLruCache用于实现存储设备缓存,即磁盘缓存,它通过将缓存对象写入文件系统从而实现缓存的效果。

引入: compile 'com.jakewharton:disklrucache:2.0.2'

DiskLruCache不能通过构造方法来创建,它提供了open方法用于创建自身,如下代码:

public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)复制代码

open方法有四个参数,第一个参数表示磁盘缓存在文件系统中的存储路径。缓存路径可以选中SD卡上的缓存目录,具体是指/sdcard/Android/data/package_name/cache 目录,当应用被卸载后,此目录会一并删除,也可以存储在其他指定目录。

第二个参数表示应用的版本号,一般设为1即可。当版本号发生改变时DiskLruCache会清空之前所有的缓存文件。

第三个参数表示单个节点所对应的数据的个数,一般设为1即可。

第四个参数表示缓存的总大小。

DiskLruCache的创建:

private DiskLruCache mDiskLruCache;private static final long DISK_CACHE_SIZE=1024*1024*50;private void diskLruCache(){    File diskCacheDir=new File(getCacheDir().getPath()+"/bitmap");    if(!diskCacheDir.exists()){        diskCacheDir.mkdirs();    }    try {        mDiskLruCache=DiskLruCache.open(diskCacheDir,1,1,DISK_CACHE_SIZE);    } catch (IOException e) {        e.printStackTrace();    }}复制代码

DiskLruCache的缓存添加的操作是通过Editor完成的,Editor表示一个缓存对象的编辑对象。

DiskLruCache的缓存添加:

private void diskCache(String url){    String key=hashKeyFormUrl(url);    try {        DiskLruCache.Editor editor=mDiskLruCache.edit(key);        if(editor!=null){            OutputStream outputStream=editor.newOutputStream(0);            if(downloadUrlToStream(url,outputStream)){                editor.commit();            }else{                editor.abort();            }        }    } catch (IOException e) {        e.printStackTrace();    }}private String hashKeyFormUrl(String url){    String cacheKey;    try {        final MessageDigest messageDigest=MessageDigest.getInstance("MD5");        messageDigest.update(url.getBytes());        cacheKey=bytesToHexString(messageDigest.digest());    } catch (NoSuchAlgorithmException e) {        cacheKey=String.valueOf(url.hashCode());    }    return cacheKey;}private String bytesToHexString(byte[] bytes){    StringBuilder stringBuilder=new StringBuilder();    for(int i=0,length=bytes.length;i

DiskLruCache的缓存查找

缓存查找过程也需要将url转换为key,然后通过DiskLruCache的get方法得到一个Snapshot对象,接着再通过Snapshot对象即可得到缓存的文件输入流,有了输入流就可以得到Bitmap对象。

private void getDiskCache(String url){    Bitmap bitmap=null;    String key=hashKeyFormUrl(url);    try {        DiskLruCache.Snapshot snapshot=mDiskLruCache.get(key);        if(snapshot!=null){            FileInputStream fileInputStream= (FileInputStream) snapshot.getInputStream(0);            FileDescriptor fileDescriptor=fileInputStream.getFD();            bitmap=decodeSampleBitmapFromFileDescriptor(fileDescriptor,500,500);            if(bitmap!=null){                //显示图片或是将bitmap进行内存缓存            }        }    } catch (IOException e) {        e.printStackTrace();    }}public static Bitmap decodeSampleBitmapFromFileDescriptor(FileDescriptor fileDescriptor,int reqWidth,int reqHeight){    final BitmapFactory.Options options=new BitmapFactory.Options();    options.inJustDecodeBounds=true;    BitmapFactory.decodeFileDescriptor(fileDescriptor,null,options);    options.inSampleSize=calculateInSampleSize(options,reqWidth,reqHeight);    options.inJustDecodeBounds=false;    return BitmapFactory.decodeFileDescriptor(fileDescriptor,null,options);}public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){    int outWidth=options.outWidth;    int outHeight=options.outHeight;    int inSampleSize=1;    if(outHeight>reqHeight||outWidth>reqWidth){        final int halfHeight=outHeight/2;        final int halfWidth=outWidth/2;        while((halfHeight/inSampleSize)>=reqHeight&&(halfWidth/inSampleSize)>=reqWidth){            inSampleSize*=2;        }    }    return inSampleSize;}复制代码

关于LruCache和DiskLruCache的内部实现会在后续文章中给出 (ps:希望大家能关注下我的公众号,毕竟写作不易,可以通过公众号和我交流一些技术,还有大家对Android有哪方面想知道的可以在底下评论,我会选些支持率高的内容进行讲解。)


转载地址:http://yizda.baihongyu.com/

你可能感兴趣的文章
干货|比特币如何产生与交易
查看>>
前端处理后端接口传递过来的图片文件
查看>>
react中的可控组件与非可控组件
查看>>
回调函数
查看>>
Android基础—四大组件之Activity
查看>>
Nginx 学习笔记
查看>>
你为什么选择程序员这个职业?
查看>>
[译] 用于 iOS 的 ML Kit 教程:识别图像中的文字
查看>>
InnoDB大数据插入的优化和FULLTEXT索引性能优化的调研
查看>>
chrome 73 以及之后的版本上安装crx插件出现「程序包无效 CRX_HEADER_INVALID」的报错解决办法...
查看>>
笔试记录集
查看>>
NoSQL Manager for MongoDB破解
查看>>
ViewPager+滑动条显示
查看>>
Load和initialize方法
查看>>
js自定义Android端手势事件
查看>>
spring boot 实现监听器、过滤器、全局异常处理
查看>>
工程师、产品经理、数据工程师是如何一起工作的?
查看>>
3-31周末总结
查看>>
Android热修复原理
查看>>
解密中国互联网企业创始人,程序员打下半壁江山
查看>>