ImageLoader LruCache DisLruCache 双缓存
ngl1125
8年前
<h2><strong>缓存?</strong></h2> <p>内存缓存跟磁盘缓存,有这种一个概念,当第一次加载完数据之后保存到内存或者磁盘,当再次读取的时候。我们就可以>先去读硬盘里面的缓存,如果没有则读内存;如果在没有则去加载网络请求;</p> <h2><strong>为何要双缓存?</strong></h2> <p>可以打开微信, 然后发一个消息或者是读取一张照片,而后你再次打开着张照片的时候就直接从内存里面读取;</p> <p>之后你再关闭网络, 然后你在重新进入app你会发现一样是可以获取到之前缓存的信息的;</p> <p>那大概就是他们缓存进的不仅仅是内存还缓存到sd里面, 当没有网络的时候直接从sd里面读取缓存;</p> <h2><strong>LruCache DisLruCache;</strong></h2> <p>我们先看如下一段代码 初始化ImageLoader</p> <pre> <code class="language-java">ImageLoader imageLoader = new ImageLoader(MyQueue.getInstance(context), new ImageLoader.ImageCache() { // 根据url获取Bitmap @Override public Bitmap getBitmap(String url) { return null; } //url作为表示保存Bitmap @Override public void putBitmap(String url, Bitmap bitmap) { } })</code></pre> <p>当实例化ImageCache 重写两个方法; 根据名称就能知道两个方法的作用;</p> <p>先放上两段代码</p> <pre> <code class="language-java">private Context mContext; private LruCache<String,Bitmap> lruCache; public MyLruCache(Context context) { this.mContext = context; //最大缓存容量 int maxSize = 10 * 1024 * 1024; lruCache = new LruCache<String, Bitmap>(maxSize) { @Override protected int sizeOf(String key, Bitmap value) { return value.getHeight() * value.getRowBytes(); } }; } @Override public Bitmap getBitmap(String url) { return lruCache.get(url); } @Override public void putBitmap(String s, Bitmap bitmap) { lruCache.put(s,bitmap); }</code></pre> <p>以上就是是一个典型的内存缓存;</p> <pre> <code class="language-java">public class MySystemDiskLru { public DiskLruCache mDiskLruCache = null; private static MySystemDiskLru mySystemDiskLru; public Context context; private MySystemDiskLru(Context context) { this.context = context; try { mDiskLruCache = DiskLruCache.open(getDirectory("VolleyImageCache"), AppUtils.getVersionCode(context), 1, 10 * 1024 * 1024); } catch (IOException e) { e.printStackTrace(); } } // 单列 public static MySystemDiskLru getInstance(Context context) { if (mySystemDiskLru == null) { mySystemDiskLru = new MySystemDiskLru(context); } return mySystemDiskLru; } /** * 获取缓存地址 */ public File getDirectory(String PathName) { String path = null; if (SDCardUtils.isSDCardEnable()) { path = SDCardUtils.getSDCardPath() + PathName; } else { path = SDCardUtils.getRootDirectoryPath() + PathName; } File file = new File(path); if (file.exists()) { file.mkdirs(); } Log.i("TAG","------path-" + path); return file; } /** * 保存 **/ public void save(String url, Bitmap bitmap) { BufferedOutputStream os = null; OutputStream outputStream = null; DiskLruCache.Editor editor = null; String key = hashKeyForDisk(url); try { editor = mDiskLruCache.edit(key); if (editor != null) { os = new BufferedOutputStream(editor.newOutputStream(0)); // 利用Bitmap工具类,将Bitmap转换成输入流 os.write(BitmapUtils.compressBitmap(bitmap)); } /** 切记刷新 */ os.flush(); editor.commit(); mDiskLruCache.flush(); } catch (IOException e) { e.printStackTrace(); // 如果没成功数据回滚 try { editor.abort(); } catch (IOException e1) { e1.printStackTrace(); } } finally { if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 获取 **/ public Bitmap getBitmap(String url) { Bitmap bitmap = null; InputStream is = null; DiskLruCache.Snapshot snapshot = null; String key = hashKeyForDisk(url); try { snapshot = mDiskLruCache.get(key); // 利用了工厂将io流转换成bitmap if (snapshot != null) { is = snapshot.getInputStream(0); // Options op = new Options(); // op.inSampleSize = 4; ,new Rect(),op // try { bitmap = BitmapFactory.decodeStream(is); // } catch (OutOfMemoryError err) { // Log.e("", "====oom-----------"); // } } } catch (IOException e) { e.printStackTrace(); } finally { try { if (is != null) { is.close(); } } catch (IOException e) { e.printStackTrace(); } } return bitmap; } /** * 将Url文件转换成MD5唯一标示 */ 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.length; i++) { String hex = Integer.toHexString(0xFF & bytes[i]); if (hex.length() == 1) { sb.append('0'); } sb.append(hex); } return sb.toString(); } }</code></pre> <p>以上代码则是硬盘缓存,要注意的地方都已经写上注释了;</p> <h2><strong>那么这个缓存是在什么时候调用呢?</strong></h2> <p>这里呢其实不需要我们担心,因为ImageLoad 已经在内部帮我们做好了</p> <p>看以下我自己运行的demo;</p> <p>这是第一次使用加载图片</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/c8fd927e03d2aee57a8321d191c0929b.gif"></p> <p>可以清楚的看到加载中的图片</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/171e94b30e9df022fe732e4e5cbd029a.gif"></p> <p>这是读取缓存好的并没有出现加载中的照片,非常流畅;</p> <p> </p> <p> </p> <p>来自:http://www.jianshu.com/p/e3ce0161cfa9</p> <p> </p>