Android 图片三级缓存机制工具类封装
三级缓存分别是:
- 软引用SoftReference,cache在内存中
- 文件缓存在本地SDcard文件夹中,遇到文件名相同的图片则从本地取,且加入软引用中
- 从网络下载,并保存在本地,且加入软引用中
其中缓存的文件,其文件名经过MD5转换,去掉了文件路径中的斜杠,目前该方法全存储成png格式的,也可进一步优化。注意需要静态初始化软引用,可保证全局有效。
实现的方法是通过集成一个AsyncTask,并定制里面的内容。好像也没什么特别好说的...
在做listview列表的时候,可把这一个task加入viewholder里,这样就能保证每个控件的唯一性了,比起封装一个AsyncImageView,要更简洁一些,并且能满足使用的要求
代码如下:
/**
* 异步根据URL获取图片
* 修改加入本地缓存和软引用
* @author Jackland_zgl
*
*/
@SuppressLint("NewApi")
public class LoadingImgTask extends AsyncTask<Void, Void, Bitmap> {
public static final String URL_KEY = "url";
public static final String BITMAP_KEY = "bitmap";
public static final String ImageCacheFilePath = "/sdcard/xiaomai/ImageCache/";
private String url;
private static HashMap<String, SoftReference<Bitmap>> cache;
RefreshDelegate refreshDelegate;
/** 静态初始化软引用 */
static {
cache = new HashMap<String, SoftReference<Bitmap>>();
}
public LoadingImgTask(String url,RefreshDelegate rd) {
this.url = url;
this.refreshDelegate = rd;
}
@Override
protected Bitmap doInBackground(Void... params) {
Bitmap bm;
//1从软引用中取
bm = getBitmapFromCache(url);
if (bm!=null) {
// Log.d("image","缓存");
return bm;
}
//2从本地中取
bm = getBitmapFromLocal(ImageCacheFilePath , modifyUriToFileName(url));
if (bm!=null) {
//放入缓存
cache.put(url, new SoftReference<Bitmap>(bm));
// Log.d("image","本地");
return bm;
}
//3从网络取 ,若能取出则缓存
bm = loadImageFromNet(url);
if (bm!=null){
try {
saveImageToSD(ImageCacheFilePath+modifyUriToFileName(url),bm);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
cache.put(url, new SoftReference<Bitmap>(bm));
// Log.d("image","网络");
}
return bm;
}
@Override
protected void onPostExecute(Bitmap result) {
HashMap<String,Object> map = new HashMap<String,Object>();
map.put(RefreshDelegate.KEY_URL, url);
map.put(RefreshDelegate.KEY_BITMAP, result);
if (refreshDelegate!=null)
refreshDelegate.refresh(map);
}
/**
* 从缓存中获取图片
* @param url
*/
public Bitmap getBitmapFromCache(String url) {
Bitmap bitmap = null;
if (cache.containsKey(url)) {
bitmap = cache.get(url).get();
}
return bitmap;
}
/**
* 从本地获取
* @param path
* @param url
* @return
*/
public Bitmap getBitmapFromLocal(String path,String url){
return BitmapFactory.decodeFile(path+url);
}
/**
* 从网络读取
* @param url
* @return
*/
public static Bitmap loadImageFromNet(String url) {
URL m;
InputStream i = null;
if (url == null) {
return null;
}
try {
m = new URL(url);
i = (InputStream) m.getContent();
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e2) {
e2.printStackTrace();
}
if (i == null) {
return null;
}
return BitmapFactory.decodeStream(i);
}
/**
* 写图片文件到SD卡
*
* @throws IOException
*/
public static void saveImageToSD(String filePath,
Bitmap bitmap) throws IOException {
Log.d("image","存在本地:"+filePath);
if (bitmap != null) {
File file = new File(filePath.substring(0,
filePath.lastIndexOf(File.separator)));
if (!file.exists()) {
file.mkdirs();
}
FileOutputStream fos = new FileOutputStream(filePath);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.PNG, 100, stream);
fos.write(stream.toByteArray());
fos.close();
}
}
/**
* 修改URL里的斜杠
* @param Url
* @return
*/
public static String modifyUriToFileName(String Url){
// String mUrl = Url.replaceAll("/", "_").replaceAll("\\.", "-").replaceAll(":", "_")+".jpg";
String mUrl = MD5Util.md5(Url)+".png";
return mUrl;
}
/**
* 刷新代理
* @author Jackland_zgl
*
*/
public interface RefreshDelegate{
public static String KEY_URL="url";
public static String KEY_BITMAP="bitmap";
public int refresh(HashMap<String,Object> result);
}
}
关于异步加载图片,下面的几篇博客可供参考:
http://www.iteye.com/topic/1118828
http://blog.csdn.net/geniusxiaoyu/article/details/7470163
http://blog.csdn.net/zshshuai/article/details/7798086
http://www.2cto.com/kf/201403/283382.html
以上几篇代码没有提到LRU的实现,使用LRU可以真正的吸取内存空间做缓存,但是目前我实现的代码不怎么有效,在此处mark一下,调成功之后再更新这个封装类
文章为原创,转载请注明出处。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。