大家在做项目时有可能会对图片做一些缓存,不必重复的请求数据。图片的缓存有三级,一是软件的内存中,二是手机中的SD卡,最后才是我们的网络请求,其实这点不算缓存。暂且把它归纳进来吧!这个图片缓存的思路是这样的:1.一级缓存在cache集合中用KEY值查找,有:显示否则进入二级查找。2.二级缓存在本地SD卡中是否有图片路径,有:显示并添加到一级缓存,否:进入三级请求。3.三级缓存通过URL网络请求加载,有:显示并添加到一二级缓存中,否则显示错误加载图片。按着这个思路往下做就轻松了,比较简单的一种实现方法,就直接贴代码:
public class ImageLoadCache {
private Context context;
private int loadingRes; //加载中的图片
private int ErroRes; //加载失败的图片
private Map<String, Bitmap> cache = new HashMap<>(); //内存缓存集合
ImageLoadCache(Context context, int loadingRes, int ErroRes) {
this.context = context;
this.loadingRes = loadingRes;
this.ErroRes = ErroRes;
}
public void LoadImge(String Imgpath, ImageView view) {
view.setTag(Imgpath); //给最新的ImageView设置最新图片路径的标识
Bitmap bitmap = null;
//一级缓存
bitmap = getFirstBitmap(Imgpath);
if (bitmap != null) {
view.setImageBitmap(bitmap);
return;
}
//二级缓存
bitmap = getSecondBitmap(Imgpath);
if (bitmap != null) {
view.setImageBitmap(bitmap);
cache.put(Imgpath, bitmap);
return;
}
//三级分线程
getThreeBitmap(Imgpath, view);
}
public Bitmap getSecondBitmap(String Imgpath) {
//二级缓存,可以再这里判断手机是否有SD卡
String SdPath = context.getExternalFilesDir(null).getAbsolutePath();
String subPath = Imgpath.substring(Imgpath.lastIndexOf("/") + 1);
String filePath = SdPath + "/" + subPath;
return BitmapFactory.decodeFile(filePath);
}
public Bitmap getFirstBitmap(String Imgpath) {
return cache.get(Imgpath);
}
public void getThreeBitmap(final String Imgpath, final ImageView view) {
final String newPathImg = (String) view.getTag();
new AsyncTask<Void, Void, Bitmap>() {
//联网请求得到bitmap对象
@Override
protected Bitmap doInBackground(Void... params) {
//在分线程执行, 可能需要等待一定时间才会执行
//在等待的过程中imageView中的tag值就有可能改变了
//如果改变了, 就不应该再去加载图片(此图片此时不需要显示)就直接返回null
Bitmap bitmap = null;
try {
if (newPathImg != Imgpath) {
return null;
}
//得到连接
URL url = new URL(Imgpath);
HttpURLConnection connect = (HttpURLConnection) url.openConnection();
//设置
connect.setReadTimeout(5000);
connect.setConnectTimeout(5000);
//连接
connect.connect();
//发请求读取返回的数据并封装为bitmap
int responseCode = connect.getResponseCode();
if (responseCode == 200) {
InputStream is = connect.getInputStream();//获取图片流
bitmap = BitmapFactory.decodeStream(is);
is.close(); //流关闭
if (bitmap != null) {
//缓存到一级缓存(分线程)
cache.put(Imgpath, bitmap);
//缓存到二级缓存(分线程)
String SdPath = context.getExternalFilesDir(null).getAbsolutePath();
String subPath = Imgpath.substring(Imgpath.lastIndexOf("/") + 1);
String filePath = SdPath + "/" + subPath;
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(filePath));//通过压缩的方式存入
}
}
connect.disconnect(); //断开连接
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onPreExecute() {
view.setImageResource(loadingRes);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
//这里也要判断是否为当前的图片路径,否则直接返回
String newPathImgs = (String) view.getTag();
if (newPathImgs != Imgpath) {
return;
}
if (bitmap == null) {
view.setImageResource(ErroRes);
} else {
view.setImageBitmap(bitmap);
}
}
}.execute();
}
}
在这里设置了一个view的标识符,主要是判断传入进来的图片路径和当前的view是否相等,这种情况在listview中item复用的时候会出现,如果不加这个标识则会出现图片加载过程中的闪现。这个原因就是item复用时imgeview加载的是不同的图片路径,所以就会当不同路径不同的
imgeview就直接return掉,所以这个添加view的标识符是相当重要的。