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

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

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

,更不能拉伸图片。

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


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

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



    public Bitmap loadBitmap(final String imageUrl,final ImageCallBack imageCallBack) {
            SoftReference<Bitmap> reference = imageMap.get(imageUrl);
            if(reference != null) {
                if(reference.get() != null) {
                    return reference.get();
                }
            }
            final Handler handler = new Handler() {
                public void handleMessage(final android.os.Message msg) {
                    //加入到缓存中
                    Bitmap bitmap = (Bitmap)msg.obj;
                    imageMap.put(imageUrl, new SoftReference<Bitmap>(bitmap));
                    if(imageCallBack != null) {
                        imageCallBack.getBitmap(bitmap);
                    }
                }
            };
            new Thread(){
                public void run() {
                    Message message = handler.obtainMessage();
                    message.obj = downloadBitmap(imageUrl);
                    handler.sendMessage(message);
                }
            }.start();
            return null ;
        }

        // 从网上下载图片
        private Bitmap downloadBitmap (String imageUrl) {
            Bitmap bitmap = null;
            try {
                bitmap = BitmapFactory.decodeStream(new URL(imageUrl).openStream());
                return bitmap ;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        public interface ImageCallBack{
            void getBitmap(Bitmap bitmap);
        }


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


    private LruCache<String, Bitmap> mMemoryCache;
    private LruCacheUtils() {
            if (mMemoryCache == null)
                mMemoryCache = new LruCache<String, Bitmap>(
                        MAXMEMONRY / 8) {
                    @Override
                    protected int sizeOf(String key, Bitmap bitmap) {
                        // 重写此方法来衡量每张图片的大小,默认返回图片数量。
                        return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
                    }

                    @Override
                    protected void entryRemoved(boolean evicted, String key,
                            Bitmap oldValue, Bitmap newValue) {
                        Log.v("tag", "hard cache is full , push to soft cache");
                      
                    }
                };
        }


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


    public void clearCache() {
            if (mMemoryCache != null) {
                if (mMemoryCache.size() > 0) {
                    Log.d("CacheUtils",
                            "mMemoryCache.size() " + mMemoryCache.size());
                    mMemoryCache.evictAll();
                    Log.d("CacheUtils", "mMemoryCache.size()" + mMemoryCache.size());
                }
                mMemoryCache = null;
            }
        }

        public synchronized void addBitmapToMemoryCache(String key, Bitmap bitmap) {
            if (mMemoryCache.get(key) == null) {
                if (key != null && bitmap != null)
                    mMemoryCache.put(key, bitmap);
            } else
                Log.w(TAG, "the res is aready exits");
        }

        public synchronized Bitmap getBitmapFromMemCache(String key) {
            Bitmap bm = mMemoryCache.get(key);
            if (key != null) {
                return bm;
            }
            return null;
        }

        /**
         * 移除缓存
         *
         * @param key
         */
        public synchronized void removeImageCache(String key) {
            if (key != null) {
                if (mMemoryCache != null) {
                    Bitmap bm = mMemoryCache.remove(key);
                    if (bm != null)
                        bm.recycle();
                }
            }
        }


说到这里,我觉得有必要来进行一下比较了。
网上有很多人使用软引用加载图片的多 ,但是现在已经不再推荐使用这种方式了,
(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
    评论
在 Android 中使用内存缓存图片,可以使用 LruCache 或自定义实现的内存缓存。 1. LruCache LruCache 是 Android 提供的一个可以回收不常用的 Bitmap 对象的缓存类,它的大小是通过构造函数中传入的 maxsize 来指定的。 以下是使用 LruCache 的示例代码: ``` public class ImageCache { private LruCache<String, Bitmap> mMemoryCache; public ImageCache() { int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); int cacheSize = maxMemory / 8; // 可以根据需求进行调整 mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { // 返回 Bitmap 对象的大小,单位为 KB return bitmap.getByteCount() / 1024; } }; } public void addToMemoryCache(String key, Bitmap bitmap) { if (getFromMemoryCache(key) == null) { mMemoryCache.put(key, bitmap); } } public Bitmap getFromMemoryCache(String key) { return mMemoryCache.get(key); } } ``` 2. 自定义实现的内存缓存 自定义实现的内存缓存可以根据需求进行调整和优化,以下是一个简单的示例代码: ``` public class ImageCache { private Map<String, Bitmap> mMemoryCache; public ImageCache() { mMemoryCache = new HashMap<String, Bitmap>(); } public void addToMemoryCache(String key, Bitmap bitmap) { if (getFromMemoryCache(key) == null) { mMemoryCache.put(key, bitmap); } } public Bitmap getFromMemoryCache(String key) { return mMemoryCache.get(key); } } ``` 使用内存缓存时,需要注意内存泄漏的问题,可以在 Activity 或 Fragment 的 onDestroy() 方法中释放缓存

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值