Welcome

首页 / 移动开发 / Android / 详解Android 图片的三级缓存及图片压缩

为什么需要图片缓存
Android默认给每个应用只分配16M的内存,所以如果加载过多的图片,为了防止内存溢出,应该将图片缓存起来。图片的三级缓存分别是:
  • 内存缓存
  • 本地缓存
  • 网络缓存
其中,内存缓存应优先加载,它速度最快;本地缓存次优先加载,它速度也快;网络缓存不应该优先加载,它走网络,速度慢且耗流量。

三级缓存的具体实现
网络缓存
  • 根据图片的url去加载图片
  • 在本地和内存中缓存
  
 public class NetCacheUtils {private LocalCacheUtils mLocalCacheUtils;private MemoryCacheUtils mMemoryCacheUtils;public NetCacheUtils(LocalCacheUtils localCacheUtils,MemoryCacheUtils memoryCacheUtils) {mLocalCacheUtils = localCacheUtils;mMemoryCacheUtils = memoryCacheUtils;}/** * 从网络下载图片 ** @param ivPic * @param url */public void getBitmapFromNet(ImageView ivPic, String url) {new BitmapTask().execute(ivPic, url);// 启动AsyncTask,// 参数会在doInbackground中获取}/** * Handler和线程池的封装 ** 第一个泛型: 参数类型 第二个泛型: 更新进度的泛型, 第三个泛型是onPostExecute的返回结果 ***/class BitmapTask extends AsyncTask<Object, Void, Bitmap> {private ImageView ivPic;private String url;/** * 后台耗时方法在此执行, 子线程 */@Overrideprotected Bitmap doInBackground(Object... params) {ivPic = (ImageView) params[0];url = (String) params[1];ivPic.setTag(url);// 将url和imageview绑定return downloadBitmap(url);}/** * 更新进度, 主线程 */@Overrideprotected void onProgressUpdate(Void... values) {super.onProgressUpdate(values);}/** * 耗时方法结束后,执行该方法, 主线程 */@Overrideprotected void onPostExecute(Bitmap result) {if (result != null) {String bindUrl = (String) ivPic.getTag();if (url.equals(bindUrl)) {// 确保图片设定给了正确的imageviewivPic.setImageBitmap(result);mLocalCacheUtils.setBitmapToLocal(url, result);// 将图片保存在本地mMemoryCacheUtils.setBitmapToMemory(url, result);// 将图片保存在内存System.out.println("从网络缓存读取图片啦...");}}}}/** * 下载图片 ** @param url * @return */private Bitmap downloadBitmap(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 inputStream = conn.getInputStream();//图片压缩处理BitmapFactory.Options option = new BitmapFactory.Options();option.inSampleSize = 2;//宽高都压缩为原来的二分之一, 此参数需要根据图片要展示的大小来确定option.inPreferredConfig = Bitmap.Config.RGB_565;//设置图片格式Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);return bitmap;}} catch (Exception e) {e.printStackTrace();} finally {conn.disconnect();}return null;}}
本地缓存
两个方法:设置本地缓存,获取本地缓存

public class LocalCacheUtils {public static final String CACHE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/local_cache";/** * 从本地sdcard读图片 */public Bitmap getBitmapFromLocal(String url) {try {String fileName = MD5Encoder.encode(url);File file = new File(CACHE_PATH, fileName);if (file.exists()) {Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file));return bitmap;}} catch (Exception e) {e.printStackTrace();}return null;}/** * 向sdcard写图片 ** @param url * @param bitmap */public void setBitmapToLocal(String url, Bitmap bitmap) {try {String fileName = MD5Encoder.encode(url);File file = new File(CACHE_PATH, fileName);File parentFile = file.getParentFile();if (!parentFile.exists()) {// 如果文件夹不存在, 创建文件夹parentFile.mkdirs();}// 将图片保存在本地bitmap.compress(CompressFormat.JPEG, 100,new FileOutputStream(file));} catch (Exception e) {e.printStackTrace();}}}
内存缓存
两个方法:设置内存缓存,获取内存缓存

问题:

如果使用HashMap存储图片时,当图片越来越多时,会导致内存溢出,因为它是强引用,java的垃圾回收器不会回收。

如若改成软引用SoftReference(内存不够时,垃圾回收器会考虑回收),仍有一个问题:在android2.3+, 系统会优先将SoftReference的对象提前回收掉, 即使内存够用。

解决办法:可以用LruCache来解决上述内存不回收或提前回收的问题。least recentlly use 最少最近使用算法 它会将内存控制在一定的大小内, 超出最大值时会自动回收, 这个最大值开发者自己定
 
public class MemoryCacheUtils {// private HashMap<String, SoftReference<Bitmap>> mMemoryCache = new// HashMap<String, SoftReference<Bitmap>>();private LruCache<String, Bitmap> mMemoryCache;public MemoryCacheUtils() {long maxMemory = Runtime.getRuntime().maxMemory() / 8;// 模拟器默认是16MmMemoryCache = new LruCache<String, Bitmap>((int) maxMemory) {@Overrideprotected int sizeOf(String key, Bitmap value) {int byteCount = value.getRowBytes() * value.getHeight();// 获取图片占用内存大小return byteCount;}};}/** * 从内存读 ** @param url */public Bitmap getBitmapFromMemory(String url) {// SoftReference<Bitmap> softReference = mMemoryCache.get(url);// if (softReference != null) {// Bitmap bitmap = softReference.get();// return bitmap;// }return mMemoryCache.get(url);}/** * 写内存 ** @param url * @param bitmap */public void setBitmapToMemory(String url, Bitmap bitmap) {// SoftReference<Bitmap> softReference = new// SoftReference<Bitmap>(bitmap);// mMemoryCache.put(url, softReference);mMemoryCache.put(url, bitmap);}}
图片压缩
//图片压缩处理(在从网络获取图片的时候就进行压缩)BitmapFactory.Options option = new BitmapFactory.Options();option.inSampleSize = 2;//宽高都压缩为原来的二分之一, 此参数需要根据图片要展示的大小来确定option.inPreferredConfig = Bitmap.Config.RGB_565;//设置图片格式Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。