图片缓存之内存缓存技术LruCache,软引用

每当碰到一些大图片的时候,我们如果不对图片进行处理就会报OOM异常,
这个 问题曾经让我觉得很烦恼 ,后来终于得到了解决,
那么现在就让我和大家一起分享一下吧。
这篇博文要讲的图片缓存机制,我接触到的有两钟,一种是软引用,另一种是内存缓存技术。
先来看下两者的使用方式,再来作比较。
除了加载图片时要用到缓存处理,还有一个比较重要的步骤要做,就是要先压缩图片。

1、压缩图片
至于要压缩到什么状态就要看自己当时的处境了,压缩图片的时候既要达到一个小的值,又不能让其模糊
,更不能拉伸图片。

  1. /**
  2. * 加载内存卡图片
  3. */
  4. BitmapFactory.Options options = new BitmapFactory.Options();
  5. options.inJustDecodeBounds = true; // 设置了此属性一定要记得将值设置为false
  6. Bitmap bitmap = null;
  7. bitmap = BitmapFactory.decodeFile(url, options);
  8. int be = (int) ((options.outHeight > options.outWidth ? options.outHeight / 150
  9. : options.outWidth / 200));
  10. if (be <= 0) // 判断200是否超过原始图片高度
  11. be = 1; // 如果超过,则不进行缩放
  12. options.inSampleSize = be;
  13. options.inPreferredConfig = Bitmap.Config.ARGB_4444;
  14. options.inPurgeable = true;
  15. options.inInputShareable = true;
  16. options.inJustDecodeBounds = false;
  17. try {
  18. bitmap = BitmapFactory.decodeFile(url, options);
  19. } catch (OutOfMemoryError e) {
  20. System.gc();
  21. Log.e(TAG, "OutOfMemoryError");
  22. }

2、软引用:
只要有足够的内存,就一直保持对象,直到发现内存吃紧且没有 Strong Ref 时才回收对象。
我们可以这样定义:map里面的键是用来放图片地址的,既可以是网络上的图片地址,也可以SDcard上的图片地址 ,
map里面的值里面放的是持有软引用的Bitmap,当然如果你要放Drawable,那也是可以的。

  1. private Map<String, SoftReference<Bitmap>> imageMap
  2. = new HashMap<String, SoftReference<Bitmap>>();

接下来就让我再介绍一下如何具体加载图片:
步骤:(1)先通过URL查看缓存中是否有图片,如果有,则直接去缓存中取得。
           如果没有,就开线程重新去网上下载。
      (2)下载完了之后,就把图片放在缓存里面,方便下次可以直接从缓存中取得。

  1. public Bitmap loadBitmap(final String imageUrl,final ImageCallBack imageCallBack) {
  2. SoftReference<Bitmap> reference = imageMap.get(imageUrl);
  3. if(reference != null) {
  4. if(reference.get() != null) {
  5. return reference.get();
  6. }
  7. }
  8. final Handler handler = new Handler() {
  9. public void handleMessage(final android.os.Message msg) {
  10. //加入到缓存中
  11. Bitmap bitmap = (Bitmap)msg.obj;
  12. imageMap.put(imageUrl, new SoftReference<Bitmap>(bitmap));
  13. if(imageCallBack != null) {
  14. imageCallBack.getBitmap(bitmap);
  15. }
  16. }
  17. };
  18. new Thread(){
  19. public void run() {
  20. Message message = handler.obtainMessage();
  21. message.obj = downloadBitmap(imageUrl);
  22. handler.sendMessage(message);
  23. }
  24. }.start();
  25. return null ;
  26. }
  27. // 从网上下载图片
  28. private Bitmap downloadBitmap (String imageUrl) {
  29. Bitmap bitmap = null;
  30. try {
  31. bitmap = BitmapFactory.decodeStream(new URL(imageUrl).openStream());
  32. return bitmap ;
  33. } catch (Exception e) {
  34. e.printStackTrace();
  35. return null;
  36. }
  37. }
  1. public interface ImageCallBack{
  2. void getBitmap(Bitmap bitmap);
  3. }

2、内存缓存技术
另外一种图片缓存的方式就是内存缓存技术。在Android中,有一个叫做 LruCache 类专门用来做图片缓存处理的。
它有一个特点,当缓存的图片达到了预先设定的值的时候,那么 近期使用次数最少的图片 就会被回收掉 。
步骤:(1)要先设置缓存图片的内存大小,我这里设置为手机内存的1/8,
           手机内存的获取方式: int MAXMEMONRY = (int) (Runtime.getRuntime() .maxMemory() / 1024);
      (2)LruCache里面的键值对分别是URL和对应的图片
      (3)重写了一个叫做sizeOf的方法,返回的是图片数量。

  1. private LruCache<String, Bitmap> mMemoryCache;
  2. private LruCacheUtils() {
  3. if (mMemoryCache == null)
  4. mMemoryCache = new LruCache<String, Bitmap>(
  5. MAXMEMONRY / 8) {
  6. @Override
  7. protected int sizeOf(String key, Bitmap bitmap) {
  8. // 重写此方法来衡量每张图片的大小,默认返回图片数量。
  9. return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
  10. }
  11. @Override
  12. protected void entryRemoved(boolean evicted, String key,
  13. Bitmap oldValue, Bitmap newValue) {
  14. Log.v("tag", "hard cache is full , push to soft cache");
  15. }
  16. };
  17. }

(4)下面的方法分别是清空缓存、添加图片到缓存、从缓存中取得图片、从缓存中移除。
          移除和清除缓存是必须要做的事,因为图片缓存处理不当就会报内存溢出,所以一定要引起注意。

  1. public void clearCache() {
  2. if (mMemoryCache != null) {
  3. if (mMemoryCache.size() > 0) {
  4. Log.d("CacheUtils",
  5. "mMemoryCache.size() " + mMemoryCache.size());
  6. mMemoryCache.evictAll();
  7. Log.d("CacheUtils", "mMemoryCache.size()" + mMemoryCache.size());
  8. }
  9. mMemoryCache = null;
  10. }
  11. }
  12. public synchronized void addBitmapToMemoryCache(String key, Bitmap bitmap) {
  13. if (mMemoryCache.get(key) == null) {
  14. if (key != null && bitmap != null)
  15. mMemoryCache.put(key, bitmap);
  16. } else
  17. Log.w(TAG, "the res is aready exits");
  18. }
  19. public synchronized Bitmap getBitmapFromMemCache(String key) {
  20. Bitmap bm = mMemoryCache.get(key);
  21. if (key != null) {
  22. return bm;
  23. }
  24. return null;
  25. }
  26. /**
  27. * 移除缓存
  28. *
  29. * @param key
  30. */
  31. public synchronized void removeImageCache(String key) {
  32. if (key != null) {
  33. if (mMemoryCache != null) {
  34. Bitmap bm = mMemoryCache.remove(key);
  35. if (bm != null)
  36. bm.recycle();
  37. }
  38. }
  39. }

4、两者的比较
说到这里,我觉得有必要来进行一下比较了。
网上有很多人使用软引用加载图片的多 ,但是现在已经不再推荐使用这种方式了,
(1)因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,
     这让软引用和弱引用变得不再可靠。
(2)另外,Android 3.0 (API Level 11)中,图片的数据会存储在本地的内存当中,
     因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩溃,
所以我这里用得是LruCache来缓存图片,当存储Image的大小大于LruCache设定的值,系统自动释放内存,
这个类是3.1版本中提供的,如果你是在更早的Android版本中开发,则需要导入android-support-v4的jar包 。

后记:我一直有强调一件事件,就是人应该要不停地进步,没有人生来就会编码,
更没有人一开始就能找到很好的解决方案, 我介绍了这两种用法,其实就是想说,
这些都是我的技术进步的一个历程。如果大家有好的建议或者有什么好的看法,
记得提出来,很高兴能和大家分享。

图片缓存之内存缓存技术LruCache,软引用相关推荐

  1. Android 图片缓存之内存缓存技术LruCache,软引用

    Android 图片缓存之内存缓存技术LruCache,软引用

  2. Glide 缓存策略 内存缓存和磁盘缓存

    感恩原创:http://www.cnblogs.com/baiqiantao/p/6808457.html Glide 缓存策略 内存缓存和磁盘缓存 官方文档:https://github.com/b ...

  3. Java中缓存之内存缓存

    Java中缓存之内存缓存 1.缓存为什么要存在 应用服务器资源是有限的,数据库每秒中接受请求的次数也是有限的.如果利用有限的资源来提供尽可能大的吞吐量呢,一个办法:减少计 算量,缩短请求流程(减少网络 ...

  4. android内存优化发展——使用软引用

    整个Android开发者一定是遇到了内存溢出这个头疼的问题,一旦这个问题.很难直接决定我们的应用程序是哪里出了问题,为了找到问题的解决方案,必须累积发行通过一些内存分析工具高速定位和强大的体验,现在详 ...

  5. java map缓存6_Java内存缓存-通过Map定制简单缓存

    缓存 在程序中,缓存是一个高速数据存储层,其中存储了数据子集,且通常是短暂性存储,这样日后再次请求此数据时,速度要比访问数据的主存储位置快.通过缓存,可以高效地重用之前检索或计算的数据. 为什么要用缓 ...

  6. 磁盘缓存和内存缓存的区别

    内存缓存 高速缓存(英语:cache,英语发音:/kæʃ/ kash [1][2][3],简称缓存),其原始意义是指访问速度比一般随机存取存储器(RAM)快的一种RAM,通常它不像系统主存那样使用DR ...

  7. Android内存优化2—使用软引用和弱引用

    来自为知笔记(Wiz) 转载于:https://www.cnblogs.com/ywq-come/p/5926405.html

  8. 内存缓存和LruCache

    三级缓存之内存缓存 三级缓存 内存缓存, 优先加载, 速度最快 本地缓存, 次优先加载, 速度快 网络缓存, 不优先加载, 速度慢,浪费流量 我们需要知道: Android默认给每个app只分配16M ...

  9. 内存缓存LruCache实现原理

    自己项目中一直都是用的开源的xUtils框架,包括 BitmapUtils.DbUtils.ViewUtils和HttpUtils四大模块,这四大模块都是项目中比较常用的.最近决定研究一下 xUtil ...

最新文章

  1. [书目20130216]深入浅出WPF
  2. 【Lucene】Lucene的工作原理
  3. hdu 2896 病毒侵袭
  4. PB datawindow中的文本调整打印长度
  5. cad镂空图案切割_贺卡纸张卡片激光镂空雕花设备 激光打标机
  6. 小米实现隔空充电技术;程序员离职小技巧;GitLab 涨价|开发者周刊
  7. samba - 为 UNIX 实现的 Windows SMB/CIFS 文件服务器
  8. java md5方法 for Android
  9. BlackBerry黑莓7230/7290等常用的功能简介以及技巧分类【转载】
  10. 【HarmonyOS HiSpark IPC DIY Camera试用连载2 】一天内极速完成从开箱编译烧写到跑通hello world
  11. C语言 switch 条件语句
  12. bug-猎豹wifi提示无线网卡未打开(微星笔记本)
  13. Java入门数据类型转换(羊驼)
  14. win7设置桌面豆绿色
  15. [渝粤教育] 中国地质大学 人力资源开发与管理 复习题 (2)
  16. 大学应用计算机应用基础课程介绍,《大学计算机应用基础》课程教学大纲
  17. 监控平台设计之GraphitePrometheus存储
  18. 扫雷游戏软件测试,软件测试
  19. JS实现curry(柯里化)的四种简单方式
  20. 适合w ndows系统的游戏,【游戏经验】Wndows系统游戏“红心大战”实战技巧图解版.doc...

热门文章

  1. excel mysql日报_Excel日报自动化
  2. python 字典循环_Python字典遍历操作实例小结
  3. python群控_带你用 Python 实现自动化群控入门篇
  4. linux php mysql.so_在linux下php挂接mysql.so扩展的方法
  5. 7000 界面语言不升级_仅限今日!手把手教你C++图形界面开发|附完整代码,海量干货!...
  6. 中国文学发展史思维导图
  7. setInterval和setTimeout的区别
  8. 实现Spark集群部署 这些公司都经历了什么?
  9. 组成关系映射(注解)
  10. 设置共享,实现Linux和Windows之间的共享