首先,我是一个小菜鸟,刚学了到一点东西,虽然很小的一点东西,但我觉得应该记下来,帮助自己也希望帮到他人···
我对三级缓存的理解是,图片首先会在内存中加载,如果内存没有,则请求本地磁盘,有的话会加载到内存中一份,如果没有则请求网络,网络是费时费流量,所以会最后请求,磁盘和内存,内存加载更快,所以首先从内存中加载,所以加载顺序是内存- >磁盘- > 网络!!请求完网络,会在本地磁盘中保存一份,然后内存保存一份
1.创建一个BitmapCacheUtils类:
public class BitmapCacheUtils {
/**
* 网络缓存工具类
*/
private NetCacheUtils netCacheUtils;
/**
* 本地缓存工具类
*/
private LocalCacheUtils localCacheUtils;
/**
* 内存缓存工具类
*/
private MemoryCacheUtils memoryCacheUtils;
public BitmapCacheUtils(Handler handler) {
//首先是内存
memoryCacheUtils=new MemoryCacheUtils();
//本地
localCacheUtils=new LocalCacheUtils(memoryCacheUtils);
//网络
netCacheUtils=new NetCacheUtils(handler,localCacheUtils,memoryCacheUtils);
}
/**
* 三级缓存设计步骤
* 从内存中取图片,如果没有,则从本地加载
* 从本地文件中取图片
* 有的话向内存中保存一份,没有则请求网络
* 请求网络图片,获取图片,显示在控件上,Handler,position
* 然后向内存中村一份
* 向本地文件存一份
* @param imageUrl
* @param position
* @return
*/
public Bitmap getBitmap(String imageUrl, int position) {
//1.从内存中获取
if (memoryCacheUtils!=null){
Bitmap bitmap =memoryCacheUtils.getBitmapFromUrl(imageUrl);
if (bitmap!=null){
LogUtil.e("内存加载图片成功=="+position);
return bitmap;
}
}
//2.从本地中取图片
if (localCacheUtils!=null){
Bitmap bitmap =localCacheUtils.getBitmapFromUrl(imageUrl);
if (bitmap!=null){
LogUtil.e("本地加载图片成功=="+position);
return bitmap;
}
}
//3.从网络获取
netCacheUtils.getBitmapFromNet(imageUrl,position);
return null;
}
}
2.创建三个类,
//网络缓存
public class NetCacheUtils {
/**
* 请求图片成功
*/
public static final int SUCCESS =1;
/**
* 请求图片失败
*/
public static final int FAILURE = 2;
private final Handler handler;
/**
* 本地缓存工具类
*/
private final LocalCacheUtils localCacheUtils;
/**
* 内存缓存工具类
*/
private final MemoryCacheUtils memoryCacheUtils;
private ExecutorService service;
public NetCacheUtils(Handler handler, LocalCacheUtils localCacheUtils, MemoryCacheUtils memoryCacheUtils) {
this.handler=handler;
this.service=Executors.newFixedThreadPool(10);//创建一个固定大小的线程池,返回一个线程池服务类
this.localCacheUtils=localCacheUtils;
this.memoryCacheUtils=memoryCacheUtils;
}
public void getBitmapFromNet(String imageUrl, int position) {
service.execute(new MyRunnable(imageUrl,position));
}
private class MyRunnable implements Runnable {
private final String imageUrl;
private final int position;
public MyRunnable(String imageUrl, int position) {
this.imageUrl=imageUrl;
this.position=position;
}
@Override
public void run() {
//子线程
//请求网络图片
try {
URL url=new URL(imageUrl);
HttpURLConnection connection= (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");//只能大写
connection.setConnectTimeout(5000);
connection.setReadTimeout(4000);
connection.connect();//可写可不写
int code=connection.getResponseCode();
if (code==200){
LogUtil.e("请求成功");
InputStream is=connection.getInputStream();//获取一个输入流
Bitmap bitmap=BitmapFactory.decodeStream(is);//把输入流转成一个Bitmap对象
//显示在控件上,发消息把Bitmap发出去和position
Message msg=Message.obtain();//从队列中取一个空的消息
msg.what=SUCCESS;//请求图片成功
msg.arg1=position;
msg.obj=bitmap;
handler.sendMessage(msg);
//然后在内村中缓存一份
memoryCacheUtils.putBitmap(imageUrl,bitmap);
//然后在本地缓存一份
localCacheUtils.putBitmap(imageUrl,bitmap);
}else {
LogUtil.e("请求异常,请及时处理");
}
} catch (IOException e) {
e.printStackTrace();
Message msg=Message.obtain();
msg.what=FAILURE;
msg.arg1=position;
handler.sendMessage(msg);
}
}
}
}
public class LocalCacheUtils {
private final MemoryCacheUtils memoryCacheUtils;
public LocalCacheUtils(MemoryCacheUtils memoryCacheUtils) {
this.memoryCacheUtils=memoryCacheUtils;
}
/**
* 根据url获取图片
* @param imageUrl
* @return
*/
public Bitmap getBitmapFromUrl(String imageUrl) {
//判断sd卡是否挂载
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
//保存图片在/mnt/sdcard/News
try {
String fileName = MD5Encoder.encode(imageUrl);//fnlkajdfjasfjasdf
File file=new File(Environment.getExternalStorageDirectory()+"/News",fileName);
if (file.exists()){
FileInputStream is=new FileInputStream(file);
Bitmap bitmap=BitmapFactory.decodeStream(is);
if (bitmap!=null){
memoryCacheUtils.putBitmap(imageUrl,bitmap);
LogUtil.e("把图片从本地保存到内存中");
}
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
LogUtil.e("图片获取失败");
}
}
return null;
}
/**
* 根据url保存图片
* @param imageUrl url
* @param bitmap 图片
*/
public void putBitmap(String imageUrl, Bitmap bitmap) {
//判断sd卡是否挂载
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
//保存图片在/mnt/sdcard/News
try {
String fileName = MD5Encoder.encode(imageUrl);//fnlkajdfjasfjasdf
File file=new File(Environment.getExternalStorageDirectory()+"/News",fileName);
//本地没有这个目录要先进行创建
File parentFile = file.getParentFile();//mnt/sdcard/News
if(!parentFile.exists()){
//创建目录
parentFile.mkdirs();
}
if (!file.exists()){
file.createNewFile();
}
//保存图片
bitmap.compress(Bitmap.CompressFormat.PNG,100, new FileOutputStream(file));
} catch (Exception e) {
e.printStackTrace();
LogUtil.e("图片本地缓存失败");
}
}
}
}
public class MemoryCacheUtils {
//集合,装图片的
private LruCache<String,Bitmap> lruCache;
public MemoryCacheUtils() {
int maxSize= (int) (Runtime.getRuntime().maxMemory()/8);//如果这里写一个1024;
lruCache=new LruCache<String,Bitmap>(maxSize){
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes()*value.getHeight();//这里也要写一个1024;
}
};
}
/**
* 根据url从内存中获取图片
* @param imageUrl
* @return
*/
public Bitmap getBitmapFromUrl(String imageUrl) {
return lruCache.get(imageUrl);
}
/**
* 根据url保存图片到lruCache集合中
* @param imageUrl 图片路径
* @param bitmap 图片
*/
public void putBitmap(String imageUrl, Bitmap bitmap) {
lruCache.put(imageUrl,bitmap);
}
}
//实例化图片缓存工具类,这是在要插入的activity中,或者fragment中
private BitmapCacheUtils bitmapCacheUtils;
//创建一个handler,需要发送到BitmapCacheUtils类中
//然后网络请求成功之后,将图片位置等的信息传过来
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case NetCacheUtils.SUCCESS://图片请求成功
int position=msg.arg1;
Bitmap bitmap= (Bitmap) msg.obj;
LogUtil.e("联网请求图片成功=="+position);
if (lv_photos_menu.isShown()) {
ImageView imageView = (ImageView) lv_photos_menu.findViewWithTag(position);
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
}else if (gv_photos_menu.isShown()){
ImageView imageView = (ImageView) gv_photos_menu.findViewWithTag(position);
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
}
break;
case NetCacheUtils.FAILURE://图片请求失败
position=msg.arg1;
LogUtil.e("联网请求图片成功=="+position);
break;
}
}
};
public InteractMenuDetailPager(Context context, NewsBean.DataEntity dataEntity) {
super(context);
this.dataEntity=dataEntity;
//实例化三级缓存类
bitmapCacheUtils=new BitmapCacheUtils(handler);
}
//从内存或者本地获取
Bitmap bitmap=bitmapCacheUtils.getBitmap(imageUrl,position);
//往适配器中插入数据
holder.iv_photos_default_menu.setImageBitmap(bitmap);
}