android 项目学习随笔十八(三级缓存)
xUtils的BitmapUtils模块用的就是三级缓存,在项目中尽量还是应用BitmapUtils
三级缓存(机制)
import com.itheima.zhsh66.R; import android.graphics.Bitmap; import android.widget.ImageView; /** * 三级缓存工具类 * */ public class MyBitmapUtils { // 网络缓存工具类 private NetCacheUtils mNetUtils; // 本地缓存工具类 private LocalCacheUtils mLocalUtils; // 内存缓存工具类 private MemoryCacheUtils mMemoryUtils; public MyBitmapUtils() { mMemoryUtils = new MemoryCacheUtils(); mLocalUtils = new LocalCacheUtils(); mNetUtils = new NetCacheUtils(mLocalUtils, mMemoryUtils); } public void display(ImageView imageView, String url) { // 设置默认加载图片 imageView.setImageResource(R.drawable.news_pic_default); // 先从内存缓存加载 Bitmap bitmap = mMemoryUtils.getBitmapFromMemory(url); if (bitmap != null) { imageView.setImageBitmap(bitmap); System.out.println("从内存读取图片啦..."); return; } // 再从本地缓存加载 bitmap = mLocalUtils.getBitmapFromLocal(url); if (bitmap != null) { imageView.setImageBitmap(bitmap); System.out.println("从本地读取图片啦..."); // 给内存设置图片 mMemoryUtils.setBitmapToMemory(url, bitmap); return; } // 从网络缓存加载 mNetUtils.getBitmapFromNet(imageView, url); } }
1、内存缓存
import android.graphics.Bitmap; import android.support.v4.util.LruCache; /** * 内存缓存工具类 * */ public class MemoryCacheUtils { // private HashMap<String, SoftReference<Bitmap>> mMemroyCache = new // HashMap<String, SoftReference<Bitmap>>(); // Android 2.3 (API Level // 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠,建议用LruCache private LruCache<String, Bitmap> mCache; public MemoryCacheUtils() { int maxMemory = (int) Runtime.getRuntime().maxMemory();// 获取虚拟机分配的最大内存 // 16M // LRU 最近最少使用, 通过控制内存不要超过最大值(由开发者指定), 来解决内存溢出 mCache = new LruCache<String, Bitmap>(maxMemory / 8) { @Override protected int sizeOf(String key, Bitmap value) { // 计算一个bitmap的大小 int size = value.getRowBytes() * value.getHeight();// 每一行的字节数乘以高度 return size; } }; } public Bitmap getBitmapFromMemory(String url) { // SoftReference<Bitmap> softReference = mMemroyCache.get(url); // if (softReference != null) { // Bitmap bitmap = softReference.get(); // return bitmap; // } return mCache.get(url); } public void setBitmapToMemory(String url, Bitmap bitmap) { // SoftReference<Bitmap> soft = new SoftReference<Bitmap>(bitmap); // mMemroyCache.put(url, soft); mCache.put(url, bitmap); } }
2、本地缓存
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import com.itheima.zhsh66.utils.MD5Encoder; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.os.Environment; /** * 本地缓存工具类 * */ public class LocalCacheUtils { // 图片缓存的文件夹 public static final String DIR_PATH = Environment .getExternalStorageDirectory().getAbsolutePath() + "/bitmap_cache66"; public Bitmap getBitmapFromLocal(String url) { try { File file = new File(DIR_PATH, MD5Encoder.encode(url)); if (file.exists()) { Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream( file)); return bitmap; } } catch (Exception e) { e.printStackTrace(); } return null; } public void setBitmapToLocal(Bitmap bitmap, String url) { File dirFile = new File(DIR_PATH); // 创建文件夹 if (!dirFile.exists() || !dirFile.isDirectory()) { dirFile.mkdirs(); } try { File file = new File(DIR_PATH, MD5Encoder.encode(url)); // 将图片压缩保存在本地,参1:压缩格式;参2:压缩质量(0-100);参3:输出流 bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(file)); } catch (Exception e) { e.printStackTrace(); } } }
3、网络缓存
import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.widget.ImageView; /** * 网络缓存 * */ public class NetCacheUtils { private LocalCacheUtils mLocalUtils; private MemoryCacheUtils mMemoryUtils; public NetCacheUtils(LocalCacheUtils localUtils, MemoryCacheUtils memoryUtils) { mLocalUtils = localUtils; mMemoryUtils = memoryUtils; } public void getBitmapFromNet(ImageView imageView, String url) { BitmapTask task = new BitmapTask(); task.execute(imageView, url); } /** * AsyncTask是线程池+handler的封装 第一个泛型: 传参的参数类型类型(和doInBackground一致) 第二个泛型: * 更新进度的参数类型(和onProgressUpdate一致) 第三个泛型: 返回结果的参数类型(和onPostExecute一致, * 和doInBackground返回类型一致) */ class BitmapTask extends AsyncTask<Object, Integer, Bitmap> { private ImageView mImageView; private String url; // 主线程运行, 预加载 @Override protected void onPreExecute() { super.onPreExecute(); } // 子线程运行, 异步加载逻辑在此方法中处理 @Override protected Bitmap doInBackground(Object... params) { mImageView = (ImageView) params[0]; url = (String) params[1]; mImageView.setTag(url);// 将imageView和url绑定在一起 // publishProgress(values)//通知进度 // 下载图片 return download(url); } // 主线程运行, 更新进度 @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } // 主线程运行, 更新主界面 @Override protected void onPostExecute(Bitmap result) { if (result != null) { // 判断当前图片是否就是imageView要的图片, 防止listview重用导致的图片错乱的情况出现 String bindUrl = (String) mImageView.getTag(); if (bindUrl.equals(url)) { // 给imageView设置图片 mImageView.setImageBitmap(result); System.out.println("网络下载图片成功!"); // 将图片保存在本地 mLocalUtils.setBitmapToLocal(result, url); // 将图片保存在内存 mMemoryUtils.setBitmapToMemory(url, result); } } } } /** * 下载图片 * * @param url */ public Bitmap download(String url) { HttpURLConnection conn = null; try { conn = (HttpURLConnection) (new URL(url).openConnection()); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); conn.setRequestMethod("GET"); 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; } }
AsyncTask是线程池+handler的封装 第一个泛型: 传参的参数类型类型(和doInBackground一致) 第二个泛型:
更新进度的参数类型(和onProgressUpdate一致) 第三个泛型: 返回结果的参数类型(和onPostExecute一致,
和doInBackground返回类型一致)
private HashMap<String, SoftReference<Bitmap>> mMemroyCache = new HashMap<String, SoftReference<Bitmap>>();
Android 2.3 (API Level9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠,建议用LruCache