当我们在app中加载大量的图片时,稍有不注意就容易出现OOM异常,为了避免出现这样的问题并保证好的用户的体验,做好缓存是非常重要,下面介绍如何为图片做三级缓存,所谓三级缓存是指在文件和内存中都做缓存,所需的数据首先从内存中做的缓存中取,当内存中没有缓存时再从文件中的缓存取,当文件中的缓存也没有时,就通过网络访问服务器取并在取到数据后,在内存和文件中都做一个缓存。
在内存中的缓存我们使用LruCache类来实现,它是一种强引用的缓存技术,它会保存最近有使用的数据,当缓存满时他会清除那些在近期没有使用的缓存数据。下面是具体的代码:
/**
* 类功能:用三级缓存为ListView中的ImageView设置图片
* @author Administrator
*
*/
public class CacheLoadBitmap {
private MainActivity context;
private ExecutorService threadPool;
//因为使用ListView来显示图片,所以每一项ImageView是复用的,为了避免图片显示的错位,使用url来标记应该显示的图片
private Map<ImageView,String> threadMap=new HashMap<ImageView, String>();
//这里获取系统可用的内存大小,并取八分之一来做LruCache的缓存大小,缓存的大小根据需要来定
private int maxSize = (int) (Runtime.getRuntime().freeMemory() /8);
//LruCache的构造器接收一个用于缓存字节数
private LruCache<String,Bitmap> cache=new LruCache<String,Bitmap>(maxSize);
public CacheLoadBitmap(MainActivity context){
this.context=context;
threadPool = Executors.newFixedThreadPool(6);
}
public void display(ImageView iv,String url){
//先从内存取
Bitmap bitmap=cache.get(url);
if(bitmap!=null){
iv.setImageBitmap(bitmap);
Log.d("load","内存取");
return;
}
//再从内存取
File file=new File(context.getCacheDir(),Md5Utils.md5(url));
if (file != null && file.exists()) {
//文件存在
//把文件转换成bitmap
bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
iv.setImageBitmap(bitmap);
//再往内存写
cache.put(url, bitmap);
Log.d("load","文件取");
return ;
}
//从网络取
URL pic_url;
try {
pic_url = new URL(url);
//刷新ImageView的url
threadMap.put(iv, url);
threadPool.submit(new LoadTask(pic_url, iv));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d("load","网络取");
}
private void saveBitmapToCacheFile(Bitmap bitmap,String url) {
File file = new File(context.getCacheDir(),Md5Utils.md5(url));
try {
bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(file));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private class LoadTask implements Runnable{
private URL url;
private ImageView iv;
public LoadTask(URL url,ImageView iv){
this.url=url;
this.iv=iv;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setReadTimeout(8000);
InputStream in = connection.getInputStream();
final Bitmap bitmap=BitmapFactory.decodeStream(in);
//1.存入内存缓存中
cache.put(url.toString(), bitmap);
//2.往本地文件缓存中添加
saveBitmapToCacheFile(bitmap,url.toString());
context.runOnUiThread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
String newurl=threadMap.get(iv);
//这里判断只有拥有最新url的图片才能显示,也就是在同一个ImageView上只有晚启动的网络图片获取线程所获取的图片才显示
if(newurl.equals(url.toString()))
iv.setImageBitmap(bitmap);
}
});
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}