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

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

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

首先是内存缓存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;
    }

猜你喜欢

转载自blog.csdn.net/asjqkkkk/article/details/78399522