之前学习过关于图片缓存的,但是总感觉不是很好,现在看了慕课网视频后,觉得虽然只是一小步的优化,但是先记录于此,以便后续继续学习。
如果没有使用图片缓存,我们每次滑动listView都会重新加载图像数据,这样不仅耗费用户的流量,而且用户体验感也不好,因此必须使用缓存,本次先学习的是内存的缓存。关于缓存图片的方法很多,我比较钟情于LruCache(),LruCache以键值对的形式,初始化时,需要设置缓存的大小K,超过这个大小的数据将会被清除(清除的数据,是那些被先加入的数据,而且最近没有使用到的数据)。LruCache内部的数据结构是LinkedHashMap存储的。使用LruCache方法非常简单,只要几步即可:
1. 定义LruCache键值对对象分别是URL和对应的图片;
2.设置Lrucache缓存的大小,重写sizeOf的方法,返回的是图片大小;
3.定义将Bitnap对象存入缓存中方法;
4.定义根据url取出缓存Bitmap对象
下面我们来逐步实现:
1. 定义LruCache键值对对象分别是URL和对应的图片
private LruCache<String, Bitmap> mCaches;
2.设置Lrucache缓存的大小,重写sizeOf的方法,返回的是图片大小
public ImageLoaders() {
//获取最大可用内存
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheSize = maxMemory / 4;
mCaches = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
//每次存入缓存时使用
return bitmap.getByteCount();
}
};
}
3.定义将Bitnap对象存入缓存中方法
/**
* 将Bitnap对象存入缓存中
*
* @param url //缓存图片的路径
* @param bitmap //缓存图片的对象
*/
public void addBitmapToCache(String url, Bitmap bitmap) {
if (getBitmapForCache(url) == null&&bitmap !=null) {
mCaches.put(url, bitmap);
}
}
4.定义根据url取出缓存Bitmap对象
/**
* 通过URL获取缓存图片,返回Bitmap对象或者返回null值
*
* @param url
* @return
*/
public Bitmap getBitmapForCache(String url) {
return mCaches.get(url);//底层linkHasMap
}
至此,LruCache初始话完成了,下面要做的就是如何操作了。
首先定义一个方法给adapter调用,在adapter只要调用这个方法就好。
/**
* 通过ImageView和url显示图片方法
*
* @param imageView
* @param url
*
* 调用方法:
* (1)在自定义的adapter中设置一个标记imageView.setTag(url)(注:在显示图片是先拿标记中的url和获取图片的url对比,一致时再显示图片)
* (2)调用new ImageLoader().showImageViewByAsyncTask(imageView,url);
*/
public void showImageViewByAsyncTask(ImageView imageView, String url) {
//先从缓存中获取图片
Bitmap bitmap = getBitmapForCache(url);
if (bitmap == null) {//不存在缓存中,直接开启异步任务下载
new MyAsnyTask(imageView, url).execute(url);
} else {//存在缓存中,直接显示
imageView.setImageBitmap(bitmap);
}
}
上面当图片不存在缓存中时,我们开启一个异步线程去下载,那么接下来我们就实现MyAsnyTask。
class MyAsnyTask extends AsyncTask<String, Void, Bitmap> {
private ImageView imageView;
private String url;
public MyAsnyTask(ImageView imageView, String url) {
this.imageView = imageView;
this.url = url;
}
@Override
protected Bitmap doInBackground(String... strings) {
String urlStr = strings[0];
Bitmap bitmap = getBitmapForUrl(urlStr);
//将不在缓存的图片加入缓存
addBitmapToCache(urlStr, bitmap);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
//在向主线程提交时先检查Tag避免图片错位
if (imageView.getTag().equals(url))
imageView.setImageBitmap(bitmap);
}
}
看,是不是基本完成了呢?我们还要实现异步任务中的getBitmapForUrl(urlStr)方法就好,当然在这个方法中我们还可以做很多工作,如对图片的压缩加工等,在这里,我们以最简单的方法实现即可。
/**
* 通过url用get方法获取Bitmap对象图片
*
* @param url
* @return
*/
public Bitmap getBitmapForUrl(String url) {
try {
URL u = new URL(url);
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
Bitmap bitmap = BitmapFactory.decodeStream(bis);
bis.close();
conn.disconnect();
return bitmap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
以上就是一个简单的工具类了,使用也比较简单,只需在自定义的adapter中:
imageView.setTag(url);
new ImageLoader().showImageViewByAsyncTask(imageView,url);
//不建议每次使用都new一次,最好在构造器中进行实例化
这是一个非常简单的例子,个人知识有限,也只能写出这样了,如果有写得不好的地方,欢迎指出!不喜勿喷,谢谢大家!