每当碰到一些大图片的时候,我们如果不对图片进行处理就会报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>>();

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

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);
        }

3、内存缓存技术
另外一种图片缓存的方式就是内存缓存技术。在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();
                }
            }
        }

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. 图片缓存之内存缓存技术LruCache,软引用

    每当碰到一些大图片的时候,我们如果不对图片进行处理就会报OOM异常, 这个问题曾经让我觉得很烦恼,后来终于得到了解决, 那么现在就让我和大家一起分享一下吧. 这篇博文要讲的图片缓存机制,我接触到的有两 ...

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

    每当碰到一些大图片的时候,我们如果不对图片进行处理就会报OOM异常,这个问题曾经让我觉得很烦恼,后来终于得到了解决,那么现在就让我和大家一起分享一下吧.这篇博文要讲的图片缓存机制,我接触到的有两钟,一 ...

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

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

  4. Android 图片三级缓存之内存缓存(告别软引用(SoftRefrerence)和弱引用(WeakReference))

    因为之前项目同事使用了图片三级缓存,今天整理项目的时候发现同事还是使用了软引用(SoftRefrerence)和弱引用(WeakReference),来管理在内存中的缓存.看到这个我就感觉不对了.脑海 ...

  5. 【转】图片缓存之内存缓存技术LruCache、软引用 比较

    每当碰到一些大图片的时候,我们如果不对图片进行处理就会报OOM异常,这个问题曾经让我觉得很烦恼,后来终于得到了解决,那么现在就让我和大家一起分享一下吧.这篇博文要讲的图片缓存机制,我接触到的有两钟,一 ...

  6. android WeakReference(弱引用 防止内存泄漏)与SoftReference(软引用 实现缓存机制(cache))

    在Android开发中,基本上很少有用到软引用或弱引用,这两个东东若用的很好,对自己开发的代码质量的提高有很大的帮助.若用的不好,会坑了自己.所以,在还没有真正的去了解它们之前,还是慎用比较好. 下面 ...

  7. 【安卓中的缓存策略系列】安卓缓存之内存缓存LruCache

    缓存策略在移动端设备上是非常重要的,尤其是在图片加载这个场景下,因为图片相对而言比较大会花费用户较多的流量,因此可用缓存方式来解决,即当程序第一次从网络上获取图片的时候,就将其缓存到存储设备上,这样在 ...

  8. .NET Core应用中使用分布式缓存及内存缓存

    .NET Core针对缓存提供了很好的支持 ,我们不仅可以选择将数据缓存在应用进程自身的内存中,还可以采用分布式的形式将缓存数据存储在一个“中心数据库”中.对于分布式缓存,.NET Core提供了针对 ...

  9. Android ListView 图片异步加载和图片内存缓存

    开发Android应用经常需要处理图片的加载问题.因为图片一般都是存放在服务器端,需要联网去加载,而这又是一个比较耗时的过程,所以Android中都是通过开启一个异步线程去加载.为了增加用户体验,给用 ...

随机推荐

  1. ndk-build出错,错误以及解决办法如下

    用NDK编译jni目录下的文件了,我的系统是Ubuntu10.04,NDK版本是android-ndk-r7b. 切换到工程的jni目录下执行:ndk-build(ndk-build的路径已经添加到系 ...

  2. ABBYY 识别结果的文档怎么导出

    使用ABBYY FineReader Pro for Mac OCR文字识别软件识别文档时,识别结果可以保存至一个文件.复制到剪贴板或通过电子邮件发送.可以执行下列操作:导出整个文档.仅导出所选页面. ...

  3. mvc:view-controller

    This tag is a shorcut for defining a ParameterizableViewController that immediately forwards to a vi ...

  4. Java 实现任意N阶幻方的构造

    一.关于单偶数阶幻方和双偶数阶幻方 (一)单偶数阶幻方(即当n=4k+2时) 任何4k+2 阶幻方都可由2k+1阶幻方与2×2方块复合而成,6是此类型的最小阶. 以6阶为例,可由3阶幻方与由0,1,2 ...

  5. 服务器返回的各种HTTP状态码介绍

    [摘要]HTTP状态码(HTTP Status Code)是用以表示网页服务器HTTP响应状态的3位数字代码.它由 RFC 2616 规范定义的,并得到RFC 2518.RFC 2817.RFC 22 ...

  6. 解决Navicat无法连接Oracle的问题

    G:\app\hoge\product\11.2.0\dbhome_3\BIN

  7. 那些年我们追过的C#奇葩关键字——忐忑[转载]

    原文地址:http://www.cnblogs.com/WeiGe/p/3315807.html 免责申明:本文为转载,如果伤及原作者利益,请与本博主邮箱313887852@qq.com联系并注明事宜 ...

  8. ab压测参数说明

    ab是apache自带的压力测试工具,非常实用.ab命令会创建多个并发访问线程,模拟多个访问者同时对某一URL地址进行访问.它的测试目标是基于URL的,因此,它既可以用来测试apache的负载压力,也 ...

  9. Saltstack系列4:Saltstack之Grains组件

    grains说明 grains是Saltstack最重要的组件之一,grains的作用是手机被控主机的基本信息,这些信息通常都是一些静态类的数据,包括CPU.内核.操作系统.虚拟化等,在服务器端可以根 ...

  10. Excel定位对象(按钮等)

    手头只有2003,2007应该类似首先显示控件工具箱,进入设计模式.然后按Ctrl+G,在定位条件里选对象,确定.此时所有空间即被选中,按del可删除之.