图片的三级缓存——学习笔记

来源:互联网 发布:国内域名不备案 编辑:程序博客网 时间:2024/06/14 05:43

三级缓存的好处是:可以尽量避免内存溢出,提高程序执行效率,省流量,提供用户体验
- 内存缓存: 最快
- 本地缓存: 其次
- 网络缓存: 速度最慢

  • 三级缓存设计步骤:
    * 从内存中取图片
    * 从本地文件中取图片
    向内存中保持一份
    * 请求网络图片,获取图片,显示到控件上
    * 向内存存一份
    * 向本地文件中存一份

首先是内存缓存MemoryCacheUtils:

public class MemoryCacheUtils {    //集合    private LruCache<String, Bitmap> lruCache;    public MemoryCacheUtils(){        //使用系统分配给应用最大内存的八分之一作为缓存大小        int maxSize = (int) (Runtime.getRuntime().maxMemory() / 8 / 1024);        lruCache = new LruCache<String, Bitmap>(maxSize){            @Override            protected int sizeOf(String key, Bitmap value) {//                return super.sizeOf(key, value);                return (value.getRowBytes() * value.getByteCount()) / 1024;            }        };    }    //根据Url从内存中获取图片    public Bitmap getBitmapFromUrl(String imageUrl) {        return  lruCache.get(imageUrl);    }    //根据Url保存图片到lruCache集合中去    public void putBitmap(String imageUrl, Bitmap bitmap) {        lruCache.put(imageUrl, bitmap);    }}

然后是本地缓存LocalCacheUtils:

public class LocalCacheUtils {    private final MemoryCacheUtils memoryCacheUtils;    public LocalCacheUtils(MemoryCacheUtils memoryCacheUtils) {        this.memoryCacheUtils = memoryCacheUtils;    }    /**     * 根据Url获取图片     * @param imageUrl     * @return     */    public Bitmap getBitmapFromUrl(String imageUrl) {        //判断sdcard是否挂载        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){            //保存图片在/mnt/sdcard/beijingnews/http://192.168.21.165:8080/xsxxxx.png            //保存图片在/mnt/sdcard/beijingnews/llkskljskljklsjklsllsl            try {                String fileName = MD5Encoder.encode(imageUrl);//llkskljskljklsjklsllsl                ///mnt/sdcard/beijingnews/llkskljskljklsjklsllsl                File file = new File(Environment.getExternalStorageDirectory()+"/beijingnews",fileName);                if(file.exists()){                    FileInputStream is = new FileInputStream(file);                    Bitmap bitmap = BitmapFactory.decodeStream(is);                    if(bitmap != null){                        memoryCacheUtils.putBitmap(imageUrl,bitmap);                        LogUtils.e("把从本地保持到内存中");                    }                    return  bitmap;                }            } catch (Exception e) {                e.printStackTrace();                LogUtils.e("图片获取失败");            }        }        return null;    }    /**     * 根据Url保存图片     * @param imageUrl url     * @param bitmap 图片     */    public void putBitmap(String imageUrl, Bitmap bitmap) {        //判断sdcard是否挂载        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){            //保存图片在/mnt/sdcard/beijingnews/http://192.168.21.165:8080/xsxxxx.png            //保存图片在/mnt/sdcard/beijingnews/llkskljskljklsjklsllsl            try {                String fileName = MD5Encoder.encode(imageUrl);//llkskljskljklsjklsllsl                ///mnt/sdcard/beijingnews/llkskljskljklsjklsllsl                File file = new File(Environment.getExternalStorageDirectory()+"/beijingnews",fileName);                File parentFile =  file.getParentFile();//mnt/sdcard/beijingnews                if(!parentFile.exists()){                    //创建目录                    parentFile.mkdirs();                }                if(!file.exists()){                    file.createNewFile();                }                //保存图片                bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(file));            } catch (Exception e) {                e.printStackTrace();                LogUtils.e("图片本地缓存失败");            }        }    }}

最后是网络缓存NetCacheUtils :

public class NetCacheUtils {    //请求图片成功    public static final int SUCESS = 1;    //请求图片失败    public static final int FAIL = 2;    private final Handler handler;    private final LocalCacheUtils localCacheUtils; //本地缓存工具类    private final MemoryCacheUtils memoryCacheUtils;//内存缓存工具类    private ExecutorService service; //线程池类    public NetCacheUtils(Handler handler, LocalCacheUtils localCacheUtils, MemoryCacheUtils memoryCacheUtils) {        this.handler = handler;        service = Executors.newFixedThreadPool(10);//创建固定线程池,容量为10        this.localCacheUtils = localCacheUtils;        this.memoryCacheUtils = memoryCacheUtils;    }    //联网请求得到图片    public void getBitmapFromNet(String imageUrl, int position) {//        new Thread(new MyRunnable(imageUrl, position)).start();        service.execute(new MyRunnable(imageUrl, position));    }    class MyRunnable implements Runnable{        private final String imageUrl;        private final int position;        public MyRunnable(String imageUrl, int position) {            this.imageUrl = imageUrl;            this.position = position;        }        @Override        public void run() {            //子线程            //请求网络图片            try {                URL url = new URL(imageUrl);                HttpURLConnection connection = (HttpURLConnection) url.openConnection();                connection.setRequestMethod("GET"); //只能大写                connection.setConnectTimeout(4000);                connection.setReadTimeout(4000);                connection.connect(); //可写可不写                int code =  connection.getResponseCode();                if (code == 200){                    InputStream is = connection.getInputStream();                    Bitmap bitmap = BitmapFactory.decodeStream(is); //把输入流转换成Bitmap                    //显示到控件上,把Bitmap和position发出去                    Message msg = Message.obtain();                    msg.what = SUCESS;                    msg.arg1 = position;                    msg.obj = bitmap;                    handler.sendMessage(msg);                    //在内存中缓存一份                    memoryCacheUtils.putBitmap(imageUrl, bitmap);                    //在本地中缓存一份                    localCacheUtils.putBitmap(imageUrl, bitmap);                }            } catch (IOException e) {                e.printStackTrace();                Message msg = Message.obtain();                msg.what = FAIL;                msg.arg1 = position;                handler.sendMessage(msg);            }        }    }}

然后将三者集合到一个类中BitmapCacheUtils:

public class BitmapCacheUtils {    private NetCacheUtils netCacheUtils;//网络缓存工具类    private LocalCacheUtils localCacheUtils;//本地缓存工具类    private MemoryCacheUtils memoryCacheUtils;//内存缓存工具类    public BitmapCacheUtils(Handler handler){        memoryCacheUtils = new MemoryCacheUtils();        localCacheUtils = new LocalCacheUtils(memoryCacheUtils);        netCacheUtils = new NetCacheUtils(handler, localCacheUtils, memoryCacheUtils);    }    /*三级缓存设计步骤:  * 从内存中取图片  * 从本地文件中取图片       向内存中保持一份  * 请求网络图片,获取图片,显示到控件上,Handler,position     * 向内存存一份     * 向本地文件中存一份*/    public Bitmap getBitmap(String imageUrl, int position) {        //1.从内存选取图片        if (memoryCacheUtils != null){            Bitmap bitmap = memoryCacheUtils.getBitmapFromUrl(imageUrl);            if (bitmap != null){                LogUtils.e("内存加载图片成功——" + position);                return bitmap;            }        }        //2.从本地选取图片        if (localCacheUtils != null){            Bitmap bitmap = localCacheUtils.getBitmapFromUrl(imageUrl);            if (bitmap != null){                LogUtils.e("本地加载图片成功——" + position);                return bitmap;            }        }        //3.从网络选取图片        netCacheUtils.getBitmapFromNet(imageUrl, position);        return null;    }}

最后,将文本缓存到SD卡中的方法:

//缓存文本数据    public static void putString(Context context, String key, String value) {        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {            //保存图片在/mnt/sdcard/beijingnews/http://192.168.0.103:8080/XSXXXX/png            //保存图片在/mnt/sdcard/beijingnews/hkjhsdhakdhasd(加密!!!)            try {                String fileName = MD5Encoder.encode(key);//llkskljskljklsjklsllsl                ///mnt/sdcard/beijingnews/llkskljskljklsjklsllsl                File file = new File(Environment.getExternalStorageDirectory()+"/beijingnews/files",fileName);                File parentFile =  file.getParentFile();//mnt/sdcard/beijingnews/files                if(!parentFile.exists()){                    //创建目录                    parentFile.mkdirs();                }                if(!file.exists()){                    file.createNewFile();                }                //保存文本数据                FileOutputStream fileOutputStream = new FileOutputStream(file);                fileOutputStream.write(value.getBytes());                fileOutputStream.close();            } catch (Exception e) {                e.printStackTrace();                LogUtils.e("文本本地缓存失败");            }        } else {            SharedPreferences sp = context.getSharedPreferences("atguitu", Context.MODE_PRIVATE);            sp.edit().putString(key, value).commit();        }    }    //缓存的文本信息    public static String getString(Context context, String key) {        String result = "";        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){            try {                String fileName = MD5Encoder.encode(key);//llkskljskljklsjklsllsl                ///mnt/sdcard/beijingnews/llkskljskljklsjklsllsl                File file = new File(Environment.getExternalStorageDirectory()+"/beijingnews/files",fileName);                if(file.exists()){                    FileInputStream is = new FileInputStream(file);                    ByteArrayOutputStream stream = new ByteArrayOutputStream();                    byte[] buffer = new byte[1024];                    int length;                    while ((length = is.read(buffer)) != -1){                        stream.write(buffer, 0, length);                    }                    is.close();                    stream.close();                    result = stream.toString();                    return result;                }            } catch (Exception e) {                e.printStackTrace();                LogUtils.e("图片获取失败");            }        } else {            SharedPreferences sp = context.getSharedPreferences("atguitu", Context.MODE_PRIVATE);            return sp.getString(key, ""); //这里用""空字符串,而不是null,不然会蹦        }        return result;    }