您的位置:首页 > 其它

使用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();
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: