使用LruCache和DiskLruCache实现ListView双缓存
2016-09-25 12:04
225 查看
package com.example.listviewcache; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashSet; import java.util.Set; import libcore.io.DiskLruCache; import libcore.io.DiskLruCache.Editor; import libcore.io.DiskLruCache.Snapshot; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.os.Environment; import android.support.v4.util.LruCache; import android.util.Log; import android.widget.ImageView; import android.widget.ListView; public class ImageLoader { /** * URL字符串数组 */ private String[] imageUrls; /** * LruCache 内存缓存 */ private LruCache<String, Bitmap> mMemCache; /** * DiskLruCache 外存(SD)缓存 */ private DiskLruCache mDiskCache; /** * ListView 对象 */ private ListView mLv; private Context mContext; private final static String tag = "ImageLoader"; private Set<DownloadTask> mTaskPool; // 程序内存1/8作为内存缓存 private final static int MEMORYCACHE_MAXSIZE = (int) (Runtime.getRuntime() .maxMemory() / 8); private final static int DISKORYCACHE_MAXSIZE = 1024 * 1024 * 8; // 8MB /** * construtor * @param context * @param imageUrl URL 字符串數組 * @param lv ListView 对象 */ public ImageLoader(Context context, String[] imageUrl, ListView lv) { super(); Log.w(tag, "Constructor"); this.mContext = context; this.mLv = lv; this.imageUrls = imageUrl; this.mTaskPool = new HashSet<ImageLoader.DownloadTask>(); this.mMemCache = new LruCache<String, Bitmap>(MEMORYCACHE_MAXSIZE) { @Override protected int sizeOf(String key, Bitmap value) { return value.getByteCount(); } }; this.mLv = lv; String dirName = "ImageCache"; int version = getAppVersion(); try { mDiskCache = DiskLruCache.open(getCacheDir(dirName), version, 1, DISKORYCACHE_MAXSIZE); } catch (IOException e) { e.printStackTrace(); } } /** * 获得缓存路径 * * @param fileName * 文件名 * @return 返回文件的绝对全路径 */ public File getCacheDir(String fileName) { String cachePath; if (Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { cachePath = mContext.getExternalCacheDir().getPath(); } else { cachePath = mContext.getCacheDir().getPath(); } File absFile = new File(cachePath + File.separator + fileName); Log.w(tag, "getCacheDir:"+absFile.toString()); return absFile; } /** * 获得App版本号 */ public int getAppVersion() { Log.w(tag, "getAppVersion"); try { int version = mContext.getPackageManager().getPackageInfo( mContext.getPackageName(), 0).versionCode; } catch (NameNotFoundException e) { e.printStackTrace(); } return 1; } /** * 将Bitmap 对象存入内存缓存中 * @param urlStr * @param bitmap */ public void putInMem(String urlStr, Bitmap bitmap) { Log.w(tag, "putInMem"); if (mMemCache.get(urlStr) == null) { mMemCache.put(urlStr, bitmap); } } /** * 通过URL字符串从内存中查找 * @param urlStr * @return 如果找到,返回,否则,返回NULL */ public Bitmap getFromMemCache(String urlStr) { Log.w(tag, "getFomMem"); Bitmap bitmap = mMemCache.get(urlStr); if (bitmap != null) { return bitmap; } else return null; } /** * 这个方法效率很低,有待改进 * @param urlStr URL 字符串 * @param bitmap URL字符串对应的Bitmap 对象 * @throws Exception */ public void putInDisk(String urlStr, Bitmap bitmap) throws Exception { Log.w(tag, "putInDisk"); // 存入 内存缓存 long tick = System.currentTimeMillis(); String key = hashKeyForDisk(urlStr); Editor editor = mDiskCache.edit(key); if (editor != null) { OutputStream os = editor.newOutputStream(0); ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); InputStream in = new ByteArrayInputStream(baos.toByteArray()); int len; byte[] buffer = new byte[2048]; while ((len = in.read(buffer)) != -1) { os.write(buffer, 0 ,len); } os.close(); in.close(); editor.commit(); long tock = System.currentTimeMillis(); Log.w(tag, "time "+(tock-tick)); } } /** * 将Bitmap 对象存入外存(SD)缓存 * @param urlStr URL 字符串 * @param in 输入流,从中读取Bitmap * @throws Exception */ public void putInDiskStream(String urlStr, InputStream in) throws Exception { Log.w(tag, "putInDisk"); // 存入 内存缓存 long tick = System.currentTimeMillis(); String key = hashKeyForDisk(urlStr); Editor editor = mDiskCache.edit(key); if (editor != null) { OutputStream os = editor.newOutputStream(0); int len; byte[] buffer = new byte[2048]; while ((len = in.read(buffer)) != -1) { os.write(buffer, 0 ,len); } os.close(); in.close(); editor.commit(); long tock = System.currentTimeMillis(); Log.w(tag, "time "+(tock-tick)); } } /** * 从外存(SD)根据URL 字符串查找 * @param urlStr * @return 如果找到,返回Bitmap对象,否则,返回NULL * @throws Exception */ public Bitmap getFromDiskCache(String urlStr) throws Exception { Log.w(tag, "getFromDisk"); // 从内存读取,首先读取到的事快照 String key = hashKeyForDisk(urlStr); Snapshot snapShot = mDiskCache.get(key); if (snapShot == null) { return null; } // 从外存读取,并存入内存缓存 snapShot = mDiskCache.get(key); InputStream is = snapShot.getInputStream(0); Bitmap bitmap = BitmapFactory.decodeStream(is); if (bitmap != null) { Log.w(tag, "Disk Fikd OK"); } return bitmap; } /** * 将byte数组转成16进制字符串 * * @param digest * @return */ private String bytesToHexString(byte[] digest) { Log.w(tag, "bytesToHex"); String hex; StringBuffer sb = new StringBuffer(); for (int i = 0; i < digest.length; i++) { hex = Integer.toHexString(0xff & digest[i]); if (hex.length() == 1) { sb.append('0'); } sb.append(hex); } return sb.toString(); } /** * 将URL字符串编码MD5 * * @param urlStr * @return */ private String hashKeyForDisk(String urlStr) { Log.w(tag, "hashKeyForDisk"); String cacheStr; try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(urlStr.getBytes()); cacheStr = bytesToHexString(md.digest()); } catch (NoSuchAlgorithmException e) { cacheStr = String.valueOf(urlStr.hashCode()); e.printStackTrace(); } return cacheStr; } /** * 根据URL从网络下载图片 * @param urlStr URL 字符串 * @return 成功则返回Bitmap 对象,否则返回NULL */ private Bitmap getBitmapFromUrl(String urlStr) { long tick = System.currentTimeMillis(); Log.w(tag, "getBitmapFromUrl"); URL url; Bitmap bitmap = null; try { url = new URL(urlStr); bitmap = BitmapFactory.decodeStream(url.openStream()); } catch (Exception e) { Log.w(tag, "下载图片异常:"+e.getMessage()); e.printStackTrace(); } long tock = System.currentTimeMillis(); Log.w(tag, "time2 "+(tock - tick)); return bitmap; } /** * 通过URL设置ImageView * @param iv ListView 对象,ImageView 的容器 * @param urlStr URL 字符串 */ public void setImageView(ImageView iv, String urlStr) { Log.w(tag, "setImageView"); Bitmap bitmap = null; try { bitmap = fetchImage(urlStr); if (iv.getTag().equals(urlStr)) { iv.setImageBitmap(bitmap); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 获得Bitmap对象后,将其设置给URL对象的ImageView, * 通过findViewWithTag找到URL对应的ImageView * @param urlStr * @param bitmap */ private void setImageViewBitmap(String urlStr, Bitmap bitmap) { Log.w(tag, "setImageViewBitmap"); ImageView iv = (ImageView) mLv.findViewWithTag(urlStr); if (iv != null) { Log.w(tag, "----find iv----"); iv.setImageBitmap(bitmap); } } /** * 对外调用,获取图片,先查找内存,然后外存,然后网络 * 如果从外存找到,则存入内存 * 如果从网络找到,则存入内存和外存 * @param urlStr * @return * @throws Exception */ public Bitmap fetchImage(String urlStr) throws Exception { Log.w(tag, "fetchImage"); //查找内存缓存,找到则返回 Bitmap bitmap = getFromMemCache(urlStr); if (bitmap != null) { return bitmap; } //查找外存(SD)缓存,找到则返回 bitmap = getFromDiskCache(urlStr); if (bitmap != null) { putInMem(urlStr, bitmap); return bitmap; } //从网上下载,如果成功,则在onPostExecute() 中直接为ImageView设置Bitmap DownloadTask task = new DownloadTask(); mTaskPool.add(task); task.execute(urlStr); return null; } /** * 异步任务类下载图片 * @author zhouweixian * */ public class DownloadTask extends AsyncTask<String, Void, Bitmap> { Bitmap bitmap; String urlStr; @Override protected Bitmap doInBackground(String... params) { Log.w(tag, "doInBackground"); urlStr = params[0]; if(isCancelled()) return null; bitmap = getBitmapFromUrl(params[0]); return bitmap; } @Override protected void onPostExecute(Bitmap result) { Log.w(tag, "onPostExecute"); //下载成功,设置ImageView setImageViewBitmap(urlStr, result); try { //存入缓存 putInMem(urlStr, result); putInDisk(urlStr, result); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } //任务完成,移除 mTaskPool.remove(this); super.onPostExecute(result); } } /** * 取消所有任务 */ public void cacelAllTasks() { Log.w(tag, "cacelAllTasks"); for (DownloadTask task : mTaskPool) { task.cancel(false); } } /** * 刷新DiskLruCache缓存 */ public void flush() { Log.w(tag, "flush"); try { if (mDiskCache != null) { mDiskCache.flush(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
相关文章推荐
- 使用LruCache和DiskLruCache实现ListView双缓存
- 使用LruCache和DiskLruCache实现内存磁盘二级图片缓存
- ListView异步记载图片+解决图片错位的问题解决+使用二级缓存(LruCache+DiskLruCache)
- Android (DiskLruCache)硬盘缓存代码实现
- Android使用LruCache、DiskLruCache实现图片缓存+图片瀑布流
- Android Volley图片缓存机制结合DiskLruCache实现磁盘缓存
- 使用lrucache实现图片内存缓存
- 解决-Glide使用DiskLruCache缓存Gif图失效
- Android 实现内存+SD卡 图片缓存策略 (LurCache+DiskLruCache)
- 如何使用ListView实现一个带有网络请求,解析,分页,缓存的公共的List页面来大大的提高工作效率
- ListView 异步加载并使用LruCache进行缓存
- 使用diskLruCache缓存数据到本地(个人笔记)
- 使用Okhttp3中的DiskLruCache进行文件缓存
- 磁盘缓存DiskLruCache的使用与源码分析
- Android缓存之DiskLruCache磁盘缓存的使用
- 怎样使用ListView实现一个带有网络请求,解析,分页,缓存的公共的List页面来大大的提高工作效率
- Android DiskLruCache磁盘缓存完全解析及使用
- LruCache和DiskLruCache实现二级缓存的自定义ImageLoader
- 使用 DiskLruCache 缓存bitmap
- 异步加载(AsyncTask异步任务、Handler、Json解析、Lrucache缓存、ListView滑动优化等来实现ListView图文混排)