android 缓存最大,Android中的缓存策略

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

缓存策略的主要流程:

当程序第一次从网络加载图片后,将其缓存到储存设备上,下一次就不用再次从网络上获取了。为了提高应用的用户体验,往往还会再内存中再缓存一份,这样当应用打算从网络请求一张图片时,首先从内存中读取,如果没有那就从储存设备中获取,如果储存设备也没有,那就从网络上下载这张图片。因为从内存中加载图片比储存设备加载要快,所以这样既提高程序的效率又为用户节约了不必要的流量开销。而这种缓存策略不仅仅适用于图片,也适用于其他文件类型。

缓存算法

目前常用的一种缓存算法是LRU(Least Recently Used),LRU是近期最少使用的算法,核心思想:当缓存满时,会优先淘汰那些近期最少使用的缓存对象。采用LRU算法的缓存有两种:LruCache和DiskLruCache,LruCache用于实现内存缓存,而DiskLruCaChe则充当了存储设备缓存。

LruCache

LruCache是一个泛型类,内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象。并且提供了get和put方法来完成缓存的获取和添加操作。强引用:直接的对象引用

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

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

初始化LruCaChe1

2

3

4

5

6

7

8int MaxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

int cacheSize = maxMemory / 8;

mMemoryCache = new LruCache(cacheSize){

protected int (String key,Bitmap bitmap){

return bitmap.getRowBytes()*bitmap.getHeight() / 1024;

}

}

在上面代码中,只需要提供缓存的总容量大小并重写sizeof方法即可。另外一些特殊情况下,还需要重写LruCache的entryRemoved方法,LruCache移除旧缓存时会调用entryRemoved方法,因此可以在entryRemoved中完成一些资源回收工作。

从LruCache中获取一个缓存对象1mMemoryCache.get(key);

向LruCache中添加一个缓存对象1mMemoryCache.put(key,bitmap)

LruCache还支持删除操作,通过remove方法即可删除一个指定的缓存对象。

DiskLruCache

1.DiskLruCache的创建

DiskLruCache提供了open方法创建1public static DiskLruCache open(File directory,int appVersion,int valueCount,long maxSize);

open方法有四个参数,其中第一个参数为磁盘缓存在文件系统中的储存路径。缓存可以选择SD卡上的缓存目录,具体为:/sdcard/Android/data/package_name/cache目录,当应用被卸载后,包名的目录会一并被删除。当然还可以选择sd卡上的其他指定路径,还可以选择data下的当前应用的目录。这里一般有个原则:如果应用卸载后就希望删除缓存文件,那么就选择SD卡上的缓存目录,如果希望保留缓存数据那就应该选择sd卡上的其他路径

第二个参数为版本号,一般设为1.当版本号改变时会清空之前的所以缓存文件。

第三个参数表示单个节点所对应的数据的个数,一般设为1即可。第四个参数为缓存的总大小。下面是典型的DiskLruCache的创建过程:1

2

3

4

5

6private static final long DISK_CACHE_SIZE = 1024 * 1024 * 50 ;

File diskCacheFile = getDiskCacheDir(mContext,"bitmap");

if(!diskCacheFile.exists()){

dislCacheFile.mkdirs();

}

mDiskLruCache = DiskLruCache.open(diskCaCheFile,1,1,DISK_CACHE_SIZE);

2.DiskLruCache的缓存添加

DiskLruCache的缓存添加的操作是通过Editor完成的,Editor表示一个缓存对象的编辑对象。这里以照片缓存为例子,首先获取图片的URL所对应的key,然后根据key就可以通过edit()来获取Editor对象,如果这个缓存正在被编辑,那么edit()会返回null,即DiskLruCache不允许同时编辑一个对象。之所以要把url转化成key,是因为图片的url很可能含有特殊的字符,这会影响url在安卓中直接使用,一般采用url的md5值作为key;1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23private String hashKeyFormUrl(String url){

String cacheKey;

try{

final MessageDigest mDigest = MessageDigest.getInstance("MD5");

mDigest.update(url.getBytes());

cacheKey = bytesToHexString(mDigest.digest());

} catch (NoSuchAlgorithmException e) {

cacheKey = String.valueof(url.hashcode());

}

return cacheKey;

}

private String bytesToHexString(byte[] bytes){

StringBuilder sb = new StringBuilder();

for(int i = 0; i < bytes.length; i++) {

String hex = Integer.toHexString(OxFF & bytes[i]);

if(hex.length() == 1) {

sb.append('0');

}

sb.append(hex);

}

return sb.toString();

}

将图片的url转成key后,就可以获得Editor对象了。对于key来说,如果当前不存在其他的Editor对象,那么edit()就会返回一个新的Editor对象,通过他可以获得文件输出流。需注意前面的diskLruCache的open方法中设置了一个节点只有一个数据,因此下面的DISK_CACHE_INDEX常量直接设置成0即可。1

2

3

4

5String key = hashkeyFormUrl(url);

DiskLruCache.Editor editor = mDiskLruCache.edit(key);

if(editor != null) {

OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);

}

有了文件输出流,那么当从网络下载图片时,图片就可以通过这个文件输出流写入到文件系统上,具体实现过程如下:1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27public boolean downloadUrlToStream(String urlString, OutputStream outputStream){

HttpURLConnection urlConnection = null;

BufferedOutputStream out = null;

BufferedInputSream in = null;

try {

final URL url = new URL(urlString);

urlConnection = (HttpURLConnection) url.openConnection();

in = new BufferedInputStream(urlConnection.getInputSream(),IO_BUFFER_SIZE);

out = new BufferedOutputStream(outputStream,IO_BUFFER_SIZE);

int b;

while ((b = in.read())!= -1) {

out.write(b);

}

return ture;

} catch (IOException e) {

e.printStack();;

}finally {

if(urlConnection != null) {

urlConnection.disConnect();

}

MyUtils.close(in);

MyUtils.close(out);

}

return false;

}

另外,必须通过Editor的commit()来提交写入操作,如果照片下载过程发生了异常,还可以通过Editor的abort()来回退整个操作。1

2

3

4

5

6

7OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);

if(downloadUrlTOSream(url,outputStream)) {

editor.commmit();

} else {

editor.abort();

}

mDiskLruCache.flush();

3.DiskLruCache的缓存查找

缓存查找的过程首先需要将url转化成key,然后通过DiskLruCache的get方法得到一个Snapshot对象,再接着通过这个对象即可获得缓存文件的输入流。进而得到Bitmap对象。为了避免加载图片导致的OOM,一般不建议直接加载原图。上文提到使用BitmapFactory.Options来加载缩放后的图片,但是这种方法之前也提到对FileInputSream存在问题,原因是FileOutput是一种有序的文件流,两次的decodeStream调用会影响文件流的位置属性,导致第二次调用decodeStream时返回了null.故为了解决这种问题,首先得获得文件描述符,再通过BitmapFactory.decodeFileDecriptor方法加载一张缩放后的照片。1

2

3

4

5

6

7

8

9

10

11Bitmap bitmap = null;

String key = hashKeyFormUrl(url);

DislLruCache.Snapshot snapShot = mDiskLruCache.get(key);

if(snapShot != null) {

FileInputStream fileInputStream = (FileInputStream) snapShot.getInputSream(DISK_CACHE_INDEXT);

FileDecriptor fileDecriptor = fileInputStream.getFD();

bitmap = mImageResizer.decodeSampledBitmapFromFileDescriptor(fileDecriptor,reqWidth,reqHeight);

if(bitmap != null) {

addBitmapToMemoryCache(key,bitmap);

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值