图片缓存之内存缓存技术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(finalString 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(newURL(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(Stringkey, 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.             };
  18.     }
     (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 synchronizedvoid addBitmapToMemoryCache(Stringkey, 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(Stringkey) {
  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 synchronizedvoid removeImageCache(Stringkey) {
  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包


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

记得提出来,很高兴能和大家分享。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值