Android图片缓存,三级缓存

来源:互联网 发布:linux shell 内置变量 编辑:程序博客网 时间:2024/04/29 21:44

1、实现原理

      采用 内存-文件-网络 三层cache机制,选择的是LruCache图片缓存。讲到LruCache不得不提一下LinkedHashMap,因为LruCache中Lru算法的实现就是通过LinkedHashMap来实现的。LinkedHashMap继承于HashMap,它使用了一个双向链表来存储Map中的Entry顺序关系,这种顺序有两种,一种是LRU顺序,一种是插入顺序,这可以由其构造函数public LinkedHashMap(int initialCapacity,float loadFactor, boolean accessOrder)指定。所以,对于get、put、remove等操作,LinkedHashMap除了要做HashMap做的事情,还做些调整Entry顺序链表的工作。LruCache中将LinkedHashMap的顺序设置为LRU顺序来实现LRU缓存,每次调用get(也就是从内存缓存中取图片),则将该对象移到链表的尾端。调用put插入新的对象也是存储在链表尾端,这样当内存缓存达到设定的最大值时,将链表头部的对象(近期最少用到的)移除。
     关于LinkedHashMap详解请前往  点击打开链接

2、具体实现 

这里写出一个图片工具类

package com.cayden.collect.utils;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Environment;import android.os.Handler;import android.util.LruCache;import android.widget.ImageView;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.URL;import java.util.LinkedHashMap;import java.util.Map;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** * Created by cuiran * Time  17/3/7 11:07 * Email cuiran2001@163.com * Description 缓存加载图片类 */public class ImageHelper {    // LRUCahce 池子    private static LruCache<String,Bitmap> mCache;    private static Handler mHandler;    private static ExecutorService mThreadPool;    private static Map<ImageView,Future<?>> mTaskTags=new LinkedHashMap<>();    private Context mContext;    public ImageHelper(Context context){        this.mContext=context;        if(mCache==null){            //最大使用的内存空间            int maxSize=(int)(Runtime.getRuntime().freeMemory()/4);            mCache=new LruCache<String,Bitmap>(maxSize){                @Override                protected int sizeOf(String key, Bitmap value) {                    return value.getRowBytes()*value.getHeight();                }            };        }        if(mHandler==null){            mHandler=new Handler();        }        if(mThreadPool==null){            mThreadPool= Executors.newFixedThreadPool(3);        }    }    /**     * 显示图片     * @param iv     * @param url     */    public void display(ImageView iv,String url){        //1、先从内存中取出来        Bitmap bitmap=mCache.get(url);        if(null!=bitmap){            iv.setImageBitmap(bitmap);            return;        }        //2、从硬盘上取       bitmap=loadBitmapFromLocal(url);        if(bitmap!=null){            //直接显示            iv.setImageBitmap(bitmap);            return;        }        //3、从网络获取图片        loadBitmapFromNet(iv,url);    }    private void loadBitmapFromNet(ImageView iv,String url){        //开线程去网络获取 使用线程池管理        //判断是否有线程为iv加载数据        Future<?> future=mTaskTags.get(iv);        if(future!=null&&!future.isCancelled()&&!future.isDone()){            //线程正在执行            future.cancel(true);            future=null;        }        future=mThreadPool.submit(new ImageLoadTask(iv,url));        mTaskTags.put(iv,future);    }    class ImageLoadTask implements  Runnable{        private String mUrl;        private ImageView iv;        public ImageLoadTask(ImageView iv,String url){            this.mUrl=url;            this.iv=iv;        }        @Override        public void run() {            try{                HttpURLConnection conn=(HttpURLConnection) new URL(mUrl).openConnection();                conn.setConnectTimeout(30 * 1000);// 设置连接服务器超时时间                conn.setReadTimeout(30 * 1000);// 设置读取响应超时时间                // 连接网络                conn.connect();                // 获取响应码                int code = conn.getResponseCode();                if(code==200){                    InputStream is=conn.getInputStream();                    //将流转换为bitmap                    Bitmap bitmap=BitmapFactory.decodeStream(is);                   //存储到本地                    write2Local(mUrl,bitmap);                    //存储到内存                    mCache.put(mUrl,bitmap);                    //图片显示:                    mHandler.post(new Runnable() {                        @Override                        public void run() {                            display(iv,mUrl);                        }                    });                }            }catch (Exception e){                e.printStackTrace();            }        }    }    /**     * 从本地加载Bitmap     * @param url     * @return     */    private Bitmap loadBitmapFromLocal(String url){        String name;        try{            name=Md5Encoder.encode(url);            File file=new File(getCacheDir(),name);            if(file.exists()){                Bitmap bitmap= BitmapFactory.decodeFile(file.getAbsolutePath());                mCache.put(url,bitmap);                return bitmap;            }        }catch (Exception e){            e.printStackTrace();        }        return null;    }    /**     * 将图片写在本地     * @param url     * @param bitmap     */    private void write2Local(String url,Bitmap bitmap){        String name;        FileOutputStream fos=null;        try {            name=Md5Encoder.encode(url);            File file=new File(getCacheDir(),name);            fos=new FileOutputStream(file);            bitmap.compress(Bitmap.CompressFormat.JPEG,100,fos);        }catch (Exception e){            e.printStackTrace();        }finally {            if(fos!=null){                try {                    fos.close();                    fos=null;                }catch (IOException e){                    e.printStackTrace();                }            }        }    }    private String getCacheDir() {        String state = Environment.getExternalStorageState();        File dir = null;        if (Environment.MEDIA_MOUNTED.equals(state)) {            // 有sd卡            dir = new File(Environment.getExternalStorageDirectory(), "/Android/data/" + mContext.getPackageName()                    + "/icon");        } else {            // 没有sd卡            dir = new File(mContext.getCacheDir(), "/icon");        }        if (!dir.exists()) {            dir.mkdirs();        }        return dir.getAbsolutePath();    }}

Md5Encoder类如下

package com.cayden.collect.utils;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;/** * Created by cuiran * Time  17/3/7 11:21 * Email cuiran2001@163.com * Description */public class Md5Encoder {    public static String encode(String password){        try{            MessageDigest digest=MessageDigest.getInstance("MD5");            byte[] result=digest.digest(password.getBytes());            StringBuilder sb=new StringBuilder();            for(int i=0;i<result.length;i++){                int number=result[i]&0xff;                String str=Integer.toHexString(number);                if(str.length()==1){                    sb.append("0");                    sb.append(str);                }else {                    sb.append(str);                }            }            return sb.toString();        }catch (NoSuchAlgorithmException e){            e.printStackTrace();            return "";        }    }}


3、如何使用

 
  String url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1488874686179&di=568604cb687e8579ac786fedc99aaff4&imgtype=0&src=http%3A%2F%2Fe.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F48540923dd54564e1e1ac2d7b7de9c82d0584fe4.jpg";  new ImageHelper(this).display(iv_test,url);

0 0