三级缓存基本原理
- 内存缓存:速度很快,不浪费流量,优先
- 本地缓存:速度快,不浪费流量,其次
- 网络缓存:速度慢,浪费流量,最后
网络缓存
思路:
- 从网络下载图片,通过AsyncTask开启线程,创建HttpURLConnection对象,把输入流转成Bitmap
因为ListView图片错乱问题,需要给ImageView设置的Tag是图片的url链接,展示图片的时候,比较tag和url是否相等
代码: /** * 网络缓存工具类 */ public class NetCacheUtils { private static final String TAG = "NetCacheUtils"; public void getBitmapFromNet(ImageView imageView, String url) { //异步下载图片 new BitmapTask(imageView, url).execute(imageView, url); } class BitmapTask extends AsyncTask<Object, Void, Bitmap> { private ImageView imageView; private String url; public BitmapTask(ImageView imageView, String url) { this.imageView = imageView; this.url = url; this.imageView.setTag(this.url); } @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected Bitmap doInBackground(Object... params) { //使用url下载图片 Bitmap bitmap = download(url); return bitmap; } @Override protected void onPostExecute(Bitmap result) { //给ImageView设置图片 //由于ListView的重用机制, // 导致某个item有可能展示它所重用的那个item的图片,导致图片错乱 //解决方案:确保当前设置的图片和当前显示的imageView完全匹配 if (result != null) { String url = (String) imageView.getTag(); //判断当前下载的图片的url是否和ImageView的url一致,如果一致,说明完全匹配 if (this.url.equals(url)) { imageView.setImageBitmap(result); Log.i(TAG, "onPostExecute: 从网络上下载图片啦"); } } } } //下载图片 private Bitmap download(String url) { HttpURLConnection conn = null; try { conn = (HttpURLConnection) new URL(url).openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(6000);//设置连接超时 conn.setReadTimeout(6000);//设置读取超时 conn.connect();//连接 int responseCode = conn.getResponseCode();//获取返回码 if (responseCode == 200) { InputStream in = conn.getInputStream();//获取输入流 //使用输入流生成Bitmap对象 Bitmap bitmap = BitmapFactory.decodeStream(in); return bitmap; } } catch (Exception e) { e.printStackTrace(); }finally { if (conn != null) { conn.disconnect(); } } return null; } }
本地缓存
思路:
- 创建本地缓存工具,首先创建缓存目录,图片url通过MD5加密作为文件名
- 从网络下载图片后,保存图片到本地
- 展示图片时,首先根据url判断本地是否有缓存,如果有就读取本地缓存,没有就从网上下载
代码:
/**
* 本地缓存工具类
*/
public class LocalCacheUtils {
//缓存文件夹
private String PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + “/zhbj_cache/”;//写缓存 public void setLocalCache(String url, Bitmap bitmap) { //将图片保存在本地文件中 File dir = new File(PATH); if (!dir.exists() || !dir.isDirectory()) { dir.mkdirs();//创建文件夹 } try { File cacheFile = new File(dir, MD5Encoder.encode(url)); //将图片压缩保存到本地,参数1:图片的格式,参数2:压缩比(0-100), 参数3:输出流 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(cacheFile)); } catch (Exception e) { e.printStackTrace(); } } //读缓存 public Bitmap getLocalCache(String url) { try { File cacheFile = new File(PATH, MD5Encoder.encode(url)); if (cacheFile.exists()) { //缓存存在 Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(cacheFile)); return bitmap; } } catch (Exception e) { e.printStackTrace(); } return null; } }
内存缓存
思路:
- 创建HashMap,key是url,value是Bitmap
- 从网络下载图片展示后,把bitmap存放到HashMap中,从本地缓存中读取图片展示后,把bitmap存放到HashMap中
展示图片时,如果内存缓存有bitmap,则不需要从本地或者网络加载图片
代码: /** * 内存缓存 */ public class MemoryCacheUtils { private Map<String, Bitmap> mHashMap = new HashMap<>(); //写缓存 public void setMemoryCache(String url, Bitmap bitmap) { mHashMap.put(url, bitmap); } //读缓存 public Bitmap getMemroyCache(String url) { return mHashMap.get(url); } }
四个引用
- 强引用,StrongReference,默认,垃圾回收器不回收
- 软引用,SoftReference,内存不足时,垃圾回收器考虑回收
- 弱引用,WeakReference,内存不足时,垃圾回收器更会考虑回收
- 虚引用,PhantomReference,内存不足时,垃圾回收器最会考虑回收
思路:
1. 把bitmap用SoftReference包装起来,然后再存放到map集合中
2. 读取时先获取SoftReference对象,再从软引用对象中获取bitmap
获取虚拟机分配的最大内存,默认16M
long maxMemory = Runtime.getRuntime().maxMemory();
maxSize,内存缓存上限
mLruCache = new LruCache<String, Bitmap>((int) (maxMemory/8)){
//返回单个对象占用内存的大小
@Override
protected int sizeOf(String key, Bitmap value) {
int byteCount = value.getRowBytes() * value.getHeight();
return byteCount;
}
};