我们在现实一个图片的时候,按照顺序来是从内存中查找是否有图片缓存,有,直接读取,无,就查找本地文件,有,直接读取,无,通过网络获取。
按照这个步骤一个一个来建立相应的类:
内存缓存
public class MemoryCacheUtils {
// //强引用
// private HashMap<String,Bitmap> memoryCache=new HashMap<>();
// //软引用
// private HashMap<String,SoftReference<Bitmap>> softMemoryCache=new HashMap<>();
private LruCache<String,Bitmap> memoryCache;
public MemoryCacheUtils() {
//构造函数来实例化一个LruCache
long maxMemory=Runtime.getRuntime().maxMemory()/8;
this.memoryCache = new LruCache<String,Bitmap>((int)maxMemory){
@Override
protected int sizeOf(String key, Bitmap value) {
int byteCount= value.getByteCount();
return byteCount;
}
};
}
/**
* 从内存读取bitmap缓存
* @param url
* @return
*/
public Bitmap getBitmapFromMemory(String url){
Bitmap bitmap=memoryCache.get(url);
return bitmap;
}
/**
* 设置Bitmap缓存到内存
* @param url
* @param bitmap
*/
public void setBitmapToMemory(String url,Bitmap bitmap){
memoryCache.put(url,bitmap);
}
}
本地缓存
public class LocalCacheUtils {
/**
* 从本地文件中通过文件名读取缓存图片文件
* @param url
* @return
*/
public Bitmap getBitmapFromLocal(String url) {
String fileName;
Bitmap bitmap=null;
try {
fileName=Md5.getMD5(url);
File file=new File(Environment.getExternalStorageDirectory()+"/ImageZip/"+fileName);
bitmap= BitmapFactory.decodeFile(file.getPath());
} catch (Exception e) {
Log.d("info","getBitmapFromLocal wrong");
e.printStackTrace();
}
return bitmap;
}
/**
* 保存缓存图片到本地
* @param url
* @param bitmap
*/
public void setBitmapToLocal(String url, Bitmap bitmap) {
try {
String fileName=Md5.getMD5(url);
File file=new File(Environment.getExternalStorageDirectory()+"/ImageZip/"+fileName);
if (!file.getParentFile().exists()){
boolean mkdirs=file.getParentFile().mkdirs();
Log.d("info","mkdirs:"+mkdirs);
}
bitmap.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(file));
}catch (Exception e){
Log.d("info","setBitmapToLocal wrong");
e.printStackTrace();
}
}
}
网络缓存
在这里网络请求图片用的是AsynTask。
public class NetCacheUtils {
//内存缓存工具类
private MemoryCacheUtils memoryCacheUtils;
//本地缓存工具类
private LocalCacheUtils localCacheUtils;
public NetCacheUtils(MemoryCacheUtils memoryCacheUtils, LocalCacheUtils localCacheUtils) {
this.memoryCacheUtils = memoryCacheUtils;
this.localCacheUtils = localCacheUtils;
}
public void getImageFromNet(ImageView imageView, String url){
new BitmapTask().execute(imageView,url);
}
class BitmapTask extends AsyncTask<Object,Integer,Bitmap>{
private ImageView imageView;
private String url;
@Override
protected Bitmap doInBackground(Object[] objects) {
imageView=(ImageView) objects[0];
url=(String) objects[1];
return downLoadBitmap(url);
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
//设置给imageView
imageView.setImageBitmap(bitmap);
//保存到本地缓存
localCacheUtils.setBitmapToLocal(url,bitmap);
//保存到内存缓存
memoryCacheUtils.setBitmapToMemory(url,bitmap);
}
}
private Bitmap downLoadBitmap(String url){
try {
URL urL = new URL(url);
HttpURLConnection httpURLConnection = (HttpURLConnection) urL.openConnection();
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setReadTimeout(10000);
if (httpURLConnection.getResponseCode() == 200) {
InputStream inputStream = httpURLConnection.getInputStream();
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize=2;
options.inPreferredConfig=Bitmap.Config.ARGB_4444;
Bitmap bitmap=BitmapFactory.decodeStream(inputStream,null,options);
inputStream.close();
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
最后将这三个缓存工具类集成一下:
public class ImageCacheUtils {
private MemoryCacheUtils memoryCacheUtils;
private LocalCacheUtils localCacheUtils;
private NetCacheUtils netCacheUtils;
public ImageCacheUtils(MemoryCacheUtils memoryCacheUtils, LocalCacheUtils localCacheUtils, NetCacheUtils netCacheUtils) {
this.memoryCacheUtils = memoryCacheUtils;
this.localCacheUtils = localCacheUtils;
this.netCacheUtils = netCacheUtils;
}
public void display(ImageView imageView,String url){
//设置占位符
imageView.setImageResource(R.mipmap.ic_launcher);
Bitmap bitmap;
//从内存缓存中找
bitmap=memoryCacheUtils.getBitmapFromMemory(url);
if (bitmap!=null){
imageView.setImageBitmap(bitmap);
Log.d("info","从内存缓存加载图片");
return;
}
//内存缓存没有,从本地缓存找
bitmap=localCacheUtils.getBitmapFromLocal(url);
if (bitmap!=null){
imageView.setImageBitmap(bitmap);
Log.d("info","从本地缓存加载图片");
//将本地获取的缓存图片保存到内存中
memoryCacheUtils.setBitmapToMemory(url,bitmap);
return;
}
//本地缓存没有,最后从网络缓存找
Log.d("info","从网络加载图片");
netCacheUtils.getImageFromNet(imageView,url);
}
}
使用:
iv_img = findViewById(R.id.iv_img);
ImageCacheUtils imageCacheUtils=new ImageCacheUtils(memoryCacheUtils,localCacheUtils,netCacheUtils);
imageCacheUtils.display(iv_img,"https://www.baidu.com/img/superlogo_c4d7df0a003d3db9b65e9ef0fe6da1ec.png");
当第一次加载图片的时候,就会用网络去请求,后面就会通过内存或者本地sd卡去加载网络图片了。
当然上面几个类可以通过内部类和单例模式来达到更好的代码结构,为了简单不搞那些了。
以上,图片的三级缓存策略
源码地址:github