Bitmap三级缓存,简单介绍,简写简用。

 

首先简介一下:

         首先你第一次进一个App时,一定是先在网络请求图片的,之后我们可以将图片保存至本地SD卡和内存,再次进入时优先访问内存中的图片缓存,若内存中没有,则加载本地SD卡中的图片。

         其中,内存缓存应优先加载,它速度最快;本地缓存次优先加载,它速度也快;网络缓存不应该优先加载,它走网络,速度慢且耗流量。(总的来说由快到慢)。

         当然有很多小伙伴问为什么要使用三级缓存,因为android默认给每一个应用分配16M的内存,如果加载过多的图片的话,为了防止内存溢出(其实要区分一下内存泄漏的概念)。

         为了搞这个三级缓存,搞得我头皮发麻,气得哦,一万只mmp飘过...... 

三级缓存有哪三级:

         1、网络缓存 从网络获取资源(异步加载)网络缓存, 不优先加载, 速度慢,浪费流量
    2、本地缓存 从本地获取数据(File存储)本地缓存, 次优先加载, 速度快
    3、内存缓存 从内存获取数据(LruCache) 内存缓存, 优先加载, 速度最快

 

接下来是我自己玩法:

首先在布局文件定义两个控件,又创建个 BitmapUtils 工具类,

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //控件id
        img1 = findViewById(R.id.img1);
        img2 = findViewById(R.id.img2);
        //调用工具类
        final BitmapUtils bitmapUtils = new BitmapUtils(this);
        bitmapUtils.display(path, img1);
        //点击事件
        img1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bitmapUtils.display(path, img2);
            }
        });
    }

 BitmapUtils工具类写法:

public class BitmapUtils {
    //分配一个Sd卡缓存路径-------->Sd卡用
    private static final String SD_CACHE_DIR = Environment.getExternalStorageDirectory() + "/photo";
    //制定一个图片缓存的内存大小------>内存用
    int maxSize = (int) (Runtime.getRuntime().maxMemory() / 8);
    //定义一个强引类型来缓存图片
    private LruCache<String, Bitmap> images = new LruCache<String, Bitmap>(maxSize) {
        @Override
        protected int sizeOf(String key, Bitmap value) {
            //返回缓存字节
            return value.getByteCount();
        }
    };


    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == 0) {
                ImageViewBitmap imageViewBitmap = (ImageViewBitmap) msg.obj;
                Bitmap bitmap = imageViewBitmap.bitmap;
                ImageView img1 = imageViewBitmap.img1;
                //修改控件上的图片
                img1.setImageBitmap(bitmap);
            }
        }
    };

    //判断SD卡文件夹是否存在--->不存在创建
    public BitmapUtils(MainActivity mainActivity) {
        File file = new File(SD_CACHE_DIR);
        if (!file.exists()) {
            file.mkdir();
        }
    }

    //加载图片做三级缓存
    public void display(String path, ImageView img1) {
        //先从内存取图片

        Bitmap bitmap = getMemory(path);
        if (bitmap != null) {
            img1.setImageBitmap(bitmap);
            Log.i("xxx", "走内存了");
        } else {
            //从sd取图片
            bitmap = getSDcard(path);
            if (bitmap != null) {
                img1.setImageBitmap(bitmap);
                Log.i("xxx", "走sd了");
            } else {
                //从网络取图片
                getInternet(path, img1);
                Log.i("xxx", "走网络了");
            }
        }
    }

    //内存获取图片
    private Bitmap getMemory(String path) {
        Bitmap bitmap = images.get(path);
        if (bitmap != null) {
            return bitmap;
        }
        return null;
    }

    //从SD卡获取图片
    private Bitmap getSDcard(String path) {
        String fileName = getFileName(path);
        File file = new File(SD_CACHE_DIR, fileName);
        //从sd取出来再缓存到内存
        Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());

        if (bitmap != null) {
            images.put(path, bitmap);
            return bitmap;
        }
        return null;
    }

    //截取文件名存入Sd卡
    private String getFileName(String path) {
        //截取最后一个“/”后的一部分作为名字返回
        return path.substring(path.lastIndexOf("/") + 1);
    }


    //网络获取图片
    private void getInternet(String path, ImageView img1) {
        //开启子线程
        new Thread(new MyRunnabale(path, img1)).start();
    }

    //Runnabale内部类
    private class MyRunnabale implements Runnable {
        String path;
        ImageView img1;

        public MyRunnabale(String path, ImageView img1) {
            this.path = path;
            this.img1 = img1;
        }

        @Override
        public void run() {
            try {
                //创建url
                URL url = new URL(path);
                //打开链接
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                //设置请求方式
                conn.setRequestMethod("GET");
                //设置延时
                conn.setConnectTimeout(5000);
                //判断状态码
                if (conn.getResponseCode() == 200) {
                    //获取网络资源
                    InputStream inputStream = conn.getInputStream();
                    //创建字节数组输出流
                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);

                    //缓存到SD卡--------------------------------------------------
                    String fileName = getFileName(path);
                    File file = new File(SD_CACHE_DIR, fileName);
                    FileOutputStream outputStream = new FileOutputStream(file);
                    BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
                    //Bitmap质量压缩---->jpeg格式---->压缩30%--->缓冲输出流
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 70, bufferedOutputStream);

                    //关流
                    bufferedOutputStream.close();
                    outputStream.close();
                    inputStream.close();

                    //只要sd里面有图片,就不会走网络了,所以内存当中就没有图片
                    images.put(path, bitmap);

                    //把img控件,bitmap封装成一个对象
                    ImageViewBitmap imageViewBitmap = new ImageViewBitmap(bitmap, img1);
                    Message message = handler.obtainMessage(0, imageViewBitmap);
                    //发送消息
                    handler.sendMessage(message);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private class ImageViewBitmap {
        Bitmap bitmap;
        ImageView img1;

        public ImageViewBitmap(Bitmap bitmap, ImageView img1) {
            this.bitmap = bitmap;
            this.img1 = img1;
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值