DiskLruCache是一套非Google官方编写,但是获得官方认证的硬盘缓存解决方案。
通常情况下,应用程序的缓存位置为/sdcard/Android/data/<application package>/cache这个路径。当程序被卸载时,此次的数据也会被一并清除。
打开缓存
创建一个DiskLruCache的实例需要调用它的open()方法,接口如下
1
| public static DiskLruCache open(File directory,int appVersion,int valueCount,long maxSize)
|
第一个参数为缓存路径,第二个参数为当前应用程序的版本号,第三个参数指定同一个key可以对应多少个缓存文件(基本使用1),第四个参数指定最多可以缓存多少字节的数据。
定义一个方法来获取缓存地址,当SD卡不存在或者SD卡不可被移除的时候,获取内部缓存地址/data/data/<application package>/cache。uniqueName是来指定不同数据的。
1 2 3 4 5 6 7 8 9
| public File getDiskCacheDir(Context context,String uniqueName){ String cachePath; if(Evrionment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemoveable()) { cachePath = context.getExternalCacheDir().getPath(); } else { cachePath = context.getCacheDir().getPath(); } return new File(cachePath + File.separator + uniqueName); }
|
获取当前应用程序版本号的方法
1 2 3 4 5 6 7 8 9
| public int getAppVersion(Context context){ try{ PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(),0); return info.versionCode; } catch (NameNotFoundException e) { e.printStackTrace(); } return 1; }
|
注:每当版本号改变,缓存路径下存储的所有数据都会被清除掉。
打开DiskLruCache的方法则为:
1 2 3 4 5 6 7 8 9 10
| DiskLruCache mDiskLruCache = null; try { File cacheDir = getDiskCacheDir(context,"bitmap"); if (!cacheDir.exists()) { cacheDir.mkdirs(); } mDiskLruCache = DiskLruCache.open(cacheDir,getAppVersion(context),1,10*1024*1024); }catch(IOException e){ e.printStackTrace(); }
|
写入缓存
比如写入一张图片,下载图片的方法
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 27 28 29 30 31 32 33
| private boolean downloadUrlToStream(String urlString,OutputStream outputStream) { HttpURLConnection urlConnection = null; BufferedOutputStream out = null; BufferedInputStream in = null; try{ final URL url = new URL(urlString); urlConnection = (HttpURLConection)url.openConnection(); in = new BufferedInputStream(urlConnection.getInputStream(),8*1024); out = new BufferedOutputStream(outputStream,8*1024); int b; while((b = in.read()) != -1) { out.write(b); } return true; } catch (final IOException) { e.printStackTrace(); } finally { if(urlConnection != null) { urlConnection.disconnect(); } try{ if(out != null){ out.close(); } if(in != null){ in.close(); } } catch(final IOException e) { e.printStackTrace(); } } return false; }
|
写入的操作需要借助DiskLruCache.Editor这个类来完成,获取方法如下
1
| public Editor edit(String key) throws IOException
|
参数key为缓存文件的文件名,为了使缓存的文件与URL一一对应,可以将URL进行MD5编码,编码后的字符串一定是唯一的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public String hashKeyForDisk(String key){ String cacheKey; try{ final MessageDigest mDigest = MessageDigest.getInstance("MD5"); mDigest.update(key.getBytes()); cacheKey = bytesToHexString(mDigest.digest()); } catch (NoSuchAlgorithmException e) { cacheKey = String.valueOf(key.hashCode()); } return cacheKey; } private String bytesToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.lengeh ; i++ ) { String hex = Integer.toHexString(0xFF & bytes[i]); if(hex.length() == 1){ sb.append('0'); } } return sb.toString(); }
|
获取Editor实例
1 2 3
| String imagUrl = "https://octodex.github.com/grinchtocat"; String key = hashKeyForDisk(imageUrl); DiskLruCache.Editor editor = mDiskLruCache.edit(key);
|
有了DiskLruCache.Editor实例后,可以调用newOutputStream()方法来创建一个输出流,传入到downloadUrlToStream()中实现下载写入的功能。注意,在写入操作完成之后,需要调用commit()方法提交才能生效,调用abort()方法表示放弃此次写入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| new Thread(new Runnable(){ @Override public void run(){ try{ String imagUrl = "https://octodex.github.com/grinchtocat"; String key = hashKeyForDisk(imageUrl); DiskLruCache.Editor editor = mDiskLruCache.edit(key); if(editor != null){ OutputStream outputStream = editor.newOutputStream(0); //设置了valueCount为1,index传0就可以了 if(downloadUrlToStream(imageUrl,outStream)) { editor.commit(); } else { editor.abort(); } } mDiskLruCache.flush(); } catch(IOException e) { e.printStackTrace(); } } }).start();
|
读取缓存
借助DiskLruCache的get方法可以获取缓存
1
| public synchronized Snapshot get(String key)throws IOException
|
返回Snapshot对象,只需要getInputStream()方法就可以得到缓存文件的输入流
1 2 3 4 5 6 7 8 9 10 11 12
| try{ String imagUrl = "https://octodex.github.com/grinchtocat"; String key = hashKeyForDisk(imageUrl); DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key); if (snapShot != null) { InputStream is = snapShot.getInputStream(0); Bitmap bitmap = BitmapFactory.decodeStream(is); mImage.setImageBitmap(bitmap); } catch (IOException e) { e.printStackTrace(); } }
|
移除缓存
通过DiskLruCache的remove()方法实现
1
| public synchronized boolean remove(String key) throws IOException
|
remove需要传入key
1 2 3 4 5 6 7
| try{ String imagUrl = "https://octodex.github.com/grinchtocat"; String key = hashKeyForDisk(imageUrl); mDiskLruCache.remove(key); }catch(IOException e){ e.printStackTrace(); }
|
其他API
- size()
返回当前缓存路径下所有缓存数据的总字节数,以byte为单位
- flush()
将内存中操作记录同步到日志文件(journal文件)当中,DiskLruCache的正常工作的前提就需要journal文件中的内容,最好在Activity的onPause()方法中调用flush()方法。
- close()
关闭DiskLruCache和open方法对应。关闭后不能再调用DiskLruCache中任何操作缓存方法,通常在Activity的onDestroy()方法中调用
- delete()
将所有DiskLruCache的缓存数据删除