Android缓存技术

来源:互联网 发布:怎样在淘宝网上开店铺 编辑:程序博客网 时间:2024/06/13 07:47

原文地址


缓存是现在Android开发中很经常碰到的一项技术.通常,缓存会分为两种:内存缓存和磁盘缓存,那么今天介绍的两个类:LruCachediskLruCache分别对应内存缓存和磁盘缓存,关于缓存,图片处理,异步任务,自定义ViewGroup等几样高级技术我会出一篇关于这几样技术的结合使用.那么今天的缓存是作为其中的一个先行课,主要就是介绍这两个类的使用.

LruCache

这个类用作内存缓存,根据缩写我们应该就可以猜出这个采用了最近最少使用算法.其实这个类的用法相当简单,因为本身通常对于缓存我们主要操作就是两个:

  • 把要缓存的对象放入缓存中
  • 从缓存中拿出对象

而,对于缓存对象我们是通过键值对去标记的.那么,针对这两个操作,我们实例讲解一下如何使用这个类.

###创建缓存

首先,使用这个类之前我们得先创建类.而创建这个类通常我们要去重写一个函数:sizeOf

    int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);    int cacheSize = maxMemory / 8;    memoryCache = new LruCache<String, Bitmap>(cacheSize) {        //计算每一个缓存对象的大小        @Override        protected int sizeOf(String key, Bitmap value) {            return value.getRowBytes() * value.getHeight() / 1024;        }    };

如上,一般我们会使用当前可用内存的1/8的内存作为缓存,在创建LruCache中我们指定了缓存的对象是bitmap,而且我们使用String类型去唯一标示每一个bitmap对象.然后我们重写sizeOf函数,这个函数是计算每一个缓存对象的大小,从上面的代码也可以看出这点,不过这里我们要注意单位,cacheSizesizeOf的单位应该要一样.


获取缓存

上面,我们已经建立缓存对象,并且开辟了控件作为缓存,现在我们来看看如何使用缓存.

把图片放入缓存

memoryCache.put("test",bitmap);

如上,我们只要给一个bitmap对象指定唯一一个key,这样子就可以把图片放入内存中,使用的时候只要 :

Bitmap bitmap = (Bitmap)memoryCache.get("test");

ok,关于LruCache的简单用法介绍就是以上这些,更多的用法请移步官网查看相关文档

DiskLruCache

这个类是专门用于硬盘缓存的.不过你首先得知道这个类并不包含在Android SDK里面,所以如果你需要使用这个类,那么你就得去下载java文件放入到你的工程中.如果你是使用Android Studio,那么只要把这个类拷贝到你的工程目录下就可以了.对于这个缓存类,一般我们会把缓存内容放在/data/data/你的包名/cache或者/sdcard/Android/data/你的包名/cache文件夹中.

DiskLruCache这个类的对象是不能使用new创建的,而是使用open函数.

DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
  • 第一个参数指定缓存路径
  • 第二个指版本号
  • 第三个参数指定同一个key可以指定多少缓存文件,一般填就够了
  • 最后一个参数指定了最大缓存容量.

一般而言,我们为了考虑到手机是否有SD卡而使用不同的缓存路径,在有SD卡的情况下使用/sdcard/Android/data/你的包名/cache,没有SD卡使用/data/data/你的包名/cache

private File getDiskCacheDir(Context context, String name) {    boolean externalStorageAvailable = Environment.getExternalStorageState()            .equals(Environment.MEDIA_MOUNTED);    String cachePath;    if (externalStorageAvailable) {        cachePath = context.getExternalCacheDir().getPath();    } else {        cachePath = context.getCacheDir().getPath();    }    return new File(cachePath + File.separator + name);}

使用上面的函数就可以判断我们应该哪个缓存路径,注意这里的name参数,这里会在cache文件夹中生成一个名字为name的文件夹,我们一般存放不同类型文件会分别设定一个文件夹,比如放置图片缓存就建立一个bitmap的文件夹,网页数据可能就建立一个web的文件夹.

写入缓存

写入缓存我们使用DiskLruCache.Editor这个类完成,但是这个类也不能new出来,而是使用edit函数获得

public Editor edit(String key)

可以看到edit接收一个key获取缓存.一般,比如对应一张图片,我们会使用他的URL地址作为key,但是直接使用URL作为key可能包含非法字符,所以一般我们会对URL进行MD5编码之后使用.

private String bytesToHexString(byte[] bytes) {    StringBuilder sb = new StringBuilder();    for (int i = 0; i < bytes.length; i++) {        String hex = Integer.toHexString(0xFF & bytes[i]);        if (1 == hex.length()) {            sb.append('0');        }        sb.append(hex);    }    return sb.toString();}//url ---> MD5private String hashKeyForUrl(String url) {    String cacheKey;    try {        MessageDigest digest = MessageDigest.getInstance("MD5");        digest.update(url.getBytes());        cacheKey = bytesToHexString(digest.digest());    } catch (Exception e) {        cacheKey = String.valueOf(url.hashCode());    }    return cacheKey;}

那么,现在我们可以把一个URL转换成MD5编码,key我们搞定了,但是我们要写入的缓存内容呢?通常我们会开启一个子线程,先把图片下载到本地,然后通过edit提交.

private boolean downloadToStream(String uriString, OutputStream outputStream) {    HttpURLConnection conn = null;    BufferedOutputStream os = null;    BufferedInputStream is = null;    try {        URL url = new URL(uriString);        conn = (HttpURLConnection) url.openConnection();        is = new BufferedInputStream(conn.getInputStream(), IO_BUFFER_SIZE);        os = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);        int b;        while ((b = is.read()) != -1) {            os.write(b);        }        return true;    } catch (Exception e) {        e.printStackTrace();    } finally {        if (conn != null) {            conn.disconnect();        }        try {            is.close();            os.close();        } catch (IOException e) {            e.printStackTrace();        }    }    return false;}

如上,根据URL,我们把图片下载保存到了outputStream流中,可是这个怎么跟edit关联上呢

DiskLruCache.Editor editor = diskLruCache.edit(key);if (editor != null) {    OutputStream outputStream = editor.newOutputStream(0);    if (downloadToStream(uri, outputStream)) {        editor.commit();    } else {        editor.abort();    }

这样子就清楚了吧,不过注意,我们在使用open函数的时候第三个参数写的是1,所以这里newOutputStream要写0就可以了.

完整代码 :

String key = hashKeyFormUrl(uri);try {    DiskLruCache.Editor editor = diskLruCache.edit(key);    if (editor != null) {        OutputStream outputStream = editor.newOutputStream(0);        if (downloadToStream(uri, outputStream)) {            editor.commit();        } else {            editor.abort();        }        diskLruCache.flush();    }} catch (IOException e) {    e.printStackTrace();}private boolean downloadToStream(String uriString, OutputStream outputStream) {    HttpURLConnection conn = null;    BufferedOutputStream os = null;    BufferedInputStream is = null;    try {        URL url = new URL(uriString);        conn = (HttpURLConnection) url.openConnection();        is = new BufferedInputStream(conn.getInputStream(), IO_BUFFER_SIZE);        os = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);        int b;        while ((b = is.read()) != -1) {            os.write(b);        }        return true;    } catch (Exception e) {        e.printStackTrace();    } finally {        if (conn != null) {            conn.disconnect();        }        try {            is.close();            os.close();        } catch (IOException e) {            e.printStackTrace();        }    }    return false;}

读取缓存

写入之后读取缓存也不是一件难事,同样,我们还是得先把URL转换成MD5编码,然后去获得缓存

String key = hashKeyFormUrl(uri);try {    DiskLruCache.Snapshot snapshot = diskLruCache.get(key);    if (snapshot != null) {        InputStream fs = (InputStream) snapshot.getInputStream(0);        Bitmap bitmap = BitmapFactory.decodeStream(fs);    }} catch (Exception e) {    e.printStackTrace();}

以上,就是关于Android中内存缓存和硬盘缓存的内容.


0 0
原创粉丝点击