首页 > 代码库 > ImageLoad(三级缓存(NetCache,MemoryCache,DiskCache),开源框架,OOM)

ImageLoad(三级缓存(NetCache,MemoryCache,DiskCache),开源框架,OOM)

ImageLoad


原创作品:未经本人允许,不得转载

前段时间写项目时遇到了一个问题,就是从网络获取图片资源的问题,总是出现OOM异常,经过几天的努力,终于处理的还算是可以使用,OOM的处理一直都是很头疼的问题.对于三级缓存的处理也是每个项目所必不可少的,所以我打算把我的学习心的写下来,以下主要针对三级缓存的原理,以及一些知识点进行详细的叙述,有不对的地方还希望大家能多加点评,指正

一.前言

首先再说三级缓存之前我们首先了解一下垃圾回收机制

下面是目前我所了解的几种引用关系

技术分享

(一).强引用(StrongReference)

  垃圾回收机制不会回收强引用所指向的内存,就算系统内存不足报出内存溢出(OOM)异常,导致系统崩溃
  垃圾回收机制也不会去回收强引用的内容来解决内存不足的问题.
//强引用,也就是一般引用,使用new关键词新建出来的引用关系
ImageView imageview = new ImageView();

(二).软引用(SoftReference)

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;
如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。
软引用可用来实现内存敏感的高速缓存

(三).弱引用(WeakReference)

    弱引用与软引用的区别在于:弱引用的对象拥有更短暂的生命周期。
    在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,
    不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 
    因此不一定会很快发现那些只具有弱引用的对象。

(四).虚引用(PhantomReference)

    “虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。
    如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

二.三级缓存原理

真如下图所示,
1.首先我们从内存中获取bitmap,
2.1.如果获取的bitmap != null,直接加载到ImageVIew
2.2.如果获取的bitmap==null,那么将继续从硬盘获取bitmap
3.1如果从硬盘获取的bitmap !=null,加载到ImageView.同时将bitmap缓存到内存缓存中
3.2如果从硬盘获取的bitmap == null,继续从网络获取
4.1从网络获取到图片,然后
4.2.加载到ImageVIew,缓存到硬盘,缓存到内存

技术分享

三.代码实现

下面是真个项目的大概框架图

技术分享

(一).BitMapUtils类

    public void disPlay(ImageView imageView, String url){
        if(this.memoryCache != null){
            bitmap = this.memoryCache.getBitmap(url);
            if(bitmap != null){
                imageView.setImageBitmap(bitmap);
                return ;
            }
        }
        if(config.isUseDiskCache()&&this.diskCache != null){
            bitmap = this.diskCache.getBitmap(url,imageView);
            if(bitmap != null){
                memoryCache.setBitmap(url,bitmap);
                imageView.setImageBitmap(bitmap);
                return;
            }
        }
        if(this.netCache != null){
            this.netCache.disPlay(imageView,url);

        }
    }

(二).三个缓存类

//1.内存缓存,使用LRUCache<Key,Values>
//使用此方法,能有效的避免内存缓存的溢出问题
//效果同使用软引用(SoftReference)相当

    public MemoryCacheUtils(ImageLoadConfig config) {
        super(config,null, null, null);

        lruCache = new LruCache<String, Bitmap>((int) config.getMaxMemory()){
            @Override//计算缓存文件已使用的大小
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight();
            }
        };
    }
    @Override
    public Bitmap getBitmap(String url) {
            return lruCache.get(url);
    }
    @Override
    public void setBitmap(String key, Bitmap value) {
        lruCache.put(key,value);
    }
}
//在内存缓存中也可以使用HashMap<Key,Values>
//此种方法使用了软引用,但是还是推荐使用LruCache<Key,Values>

    SoftReference<HashMap<Key,Values>> softhashMap = new SoftReference<HashMap<Key,Values>>();
    public Bitmap getBitmap(String url){
        return softhashMap.get(url);
    }
    public void setBitmap(Bitmap bitmap,String url){
        softhashMap.set(url,bitmap);
    }

//2.硬盘缓存:

    public Bitmap getBitmap(String url){
        return BitmapFactory.decodeFiles(filePath);
    }
    public void setBitmap(Bitmap bitmap,String url){
        File dir = new File(config.getLOCAL_PATH());
            String fileName = MD5Encoder.encode(key);
            File cacheFile = new File(dir, fileName);
             // 参1:图片格式;参2:压缩比例0-100; 参3:输出流
            value.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStreamcacheFile));

    }
//3.网络缓存,使用AsyncTask加载网络图片
 public Bitmap disPlay(final ImageView imageView, final String url) {
        asyncTask = new AsyncTask<String, Integer, Bitmap>() {
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
            }
            @Override
            protected void onProgressUpdate(Integer... values) {
                super.onProgressUpdate(values);
            }
            @Override//此方法存在于子线程可以直接进行延迟操作,加载网络数据
            protected Bitmap doInBackground(String... params) {
            //从网络下载图片
                try {
                    URL url1 = new URL(params[0].toString());
                    HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setReadTimeout(config.getREAD_TIME());
                    conn.setConnectTimeout(config.getCONNECT_TIME());
                    if(conn.getResponseCode() == 200){
                        InputStream is = conn.getInputStream();
                        BitmapFactory.Options  options = new BitmapFactory.Options();
                        options.inSampleSize = config.getInSampleSize();
                        options.inPreferredConfig = Bitmap.Config.ARGB_4444;
                        bitmap = BitmapFactory.decodeStream(is,null,options);
                        conn.disconnect();
                        is.close();
                    }
                    return bitmap;
                } catch (Exception e) {
                    e.printStackTrace();
                }

                return null;
            }

            @Override
            protected void onPostExecute(Bitmap bitmap) {
                super.onPostExecute(bitmap);
                imageView.setImageBitmap(bitmap)//把加载来的bitmap设置给ImageView
                memoryCache.setBitmap(url,bitmap);//缓存到内存
                diskCache.setBitmap(url,bitmap);//保存到硬盘
            return bitmap;
    }

注:以上代码均只写了相关代码,并没有补全,如需详细代码,请参考github开源代码

下载链接:点击下载源码

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    ImageLoad(三级缓存(NetCache,MemoryCache,DiskCache),开源框架,OOM)