实现三级缓存

博客转移到个人站点:
http://www.wangchengmeng.club/2018/02/04/%E5%AE%9E%E7%8E%B0%E4%B8%89%E7%BA%A7%E7%BC%93%E5%AD%98/

欢迎来吐槽

三级缓存

1.思想:

1.从网络上获取数据,效率比较低,速度较慢,而且需要联网

2.为了更高的提高读取已经从网络上获取过的数据,并且在没联网的情况下也可以浏览,在第一次从网络上获取数据的时候将数据存储到缓存文件中

3.为了提高读取效率,直接从内存中读取是最快的,可以将获取的数据保存到内存中(LruCache),在内存足够的情况下,系统直接从内存中读取数据,效率是比较高的,当然,当内存不足的时候,系统会回收你在内存中保存在数据,这个时候你就需要从缓存文件中读取,如果缓存文件没有的情况下,你再从网络上获取。

2.优点

1.对于读取你已经从网络上读取过的数据,使用三级缓存,可以大大提高读取数据的效率,

2.在没有联网的情况下你仍可以读取你保存的数据

3.不必每次都需要从网络上去获取数据,只是第一次访问的时候需要访问网络,节省了流量

3.实现一个三级缓存图片的工具类

1.定义一个工具类  BitmapCacheUtils并实现其构造方法

    public class BitmapCacheUtils {
        private HomeActivity mContext;
        private LruCache<String, Bitmap> lruCache;
        private ExecutorService threadPool;

        HashMap<ImageView,String> hm = new HashMap<ImageView,String>();
        public BitmapCacheUtils(HomeActivity context) {
            this.mContext = context;
            int maxSize = (int) (Runtime.getRuntime().freeMemory() / 2);  //运行的可用内存的一半
            //线程池
            threadPool = Executors.newFixedThreadPool(3);

            //1级缓存的容器   软引用
            //参数是你允许的最大缓存,你存储的数据不可以超过这个值,
            lruCache = new LruCache<String, Bitmap>(maxSize){
                @Override
                protected int sizeOf(String key, Bitmap value) {

                    //动态计算每张图片的大小
                    return value.getRowBytes() * value.getHeight();
                }

            };
        }


2.定义一个方法(根据传入的url给ImageView添加图片)

    public void display(ImageView image, String url) {

        // 首先从内存获取数据  内存有数据了 就不必去本地或者网络中获取了,提高效率
        Bitmap bitmap = lruCache.get(url);
        if(bitmap != null){
            image.setImageBitmap(bitmap);
            return;
        }

        // 从本地缓存文件中获取数据   
        Bitmap bitmap2 = getBitmapFromCache(url);   ---》3.
        if(bitmap2 != null){
            //本地有数据了,就直接本地获取,不必去网络中获取了
            image.setImageBitmap(bitmap2);
            return ;
        }

        //获取之前先将url存储在hashMap中
        hm.put(image, url);

        // 从网络获取数据
        getDataFromNet(image, url); ---》4.
    }

3.从本地读取图片的时候,如果读取有数据,也将其保存到内存中

    private Bitmap getBitmapFromCache(String url){
        //http://www.baidu.com/mm.png  url类似这钟,/在文件中是会影响到路径的读取,所以截取最后一个/后面的字符作为文件名
        File file = new File(mContext.getCacheDir(),url.substring(url.lastIndexOf("/") + 1));
        Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());

        if(bitmap != null){
            //如果本地有文件  在内存中保存一份
            lruCache.put(url, bitmap);
        }

        return bitmap;
    }

4.从网络中读取数据(耗时操作放在子线程中执行)

    private void getDataFromNet(ImageView image, String url) {

        //线程池提交任务  使用线程池 提高效率
        threadPool.submit(new Task(image,url));
    }

    //线程执行的任务类
    private class Task implements Runnable{
        public ImageView img;
        public String url;
        public Task(ImageView img ,String url){
            this.img = img;
            this.url = url;
        }
        @Override
        public void run() {
        getFromNet(img, url);  ---》5.
        }
    }

5.联网获取图片

    protected void getFromNet(final ImageView image, final String url) {

    try {
        URL cacheUrl = new URL(url);

        HttpURLConnection connection = (HttpURLConnection) cacheUrl
                .openConnection();
        connection.setConnectTimeout(5000);
        connection.setRequestMethod("GET");
        connection.connect();
        int code = connection.getResponseCode();
        if (code == 200) {
            // 请求成功
            InputStream is = connection.getInputStream();
            final Bitmap bitmap = BitmapFactory.decodeStream(is);

            // 往内存写入数据
            lruCache.put(url, bitmap);  ---》6.

            // 往本地写数据
            write2Local(bitmap, url);   ----》7.

            //子线程中不可以更新UI
            mContext.runOnUiThread(new Runnable() {

                @Override
                public void run() {

                    //在设置图片的时候,判断绑定的url是否是新的
                    if(hm.get(image).equals(url)){
                        //是新的url那就可以进行绑定了
                        image.setImageBitmap(bitmap);
                    }
                }
            });
        }

    } catch (Exception e) {
        e.printStackTrace();
    }

}


6.往内存中写入数据

    // 往内存写入数据
    lruCache.put(url, bitmap);

    主要是  LruCache这个类

    实例化:

            int maxSize = (int) (Runtime.getRuntime().freeMemory() / 2); //运行的可用内存的一半

            //1级缓存的容器   软引用
            //参数是你允许的最大缓存,你存储的数据不可以超过这个值,
            lruCache = new LruCache<String, Bitmap>(maxSize){
                @Override
                protected int sizeOf(String key, Bitmap value) {

                    //动态计算每张图片的大小
                    return value.getRowBytes() * value.getHeight();
                }

            };


7.往本地写入数据

    protected void write2Local(Bitmap bitmap, String url) {
        // 缓存文件
        File cacheDir = mContext.getCacheDir();
        File file = new File(cacheDir, url.substring(url.lastIndexOf("/") + 1));
        try {
            // 写入图片
            bitmap.compress(CompressFormat.PNG, 100,
                    new FileOutputStream(file));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring框架中的三级缓存主要是在解决Spring Bean的循环依赖问题时使用的。三级缓存实现机制涉及到Spring的BeanFactory,主要目的是为了确保即使在有循环依赖的情况下,Spring容器也能够正常工作。下面是三级缓存的一个简单介绍: 1. 第一级缓存(一级缓存):也称为单例池,是一个名为`singletonObjects`的Map,用于存放完全初始化好的Bean,即已经实例化并且已经填充了属性的Bean。这个缓存是最终获取Bean的地方。 2. 第二级缓存(二级缓存):是一个名为`earlySingletonObjects`的Map,用于存放早期的Bean引用,即还未完全初始化的Bean。如果一个Bean正在创建过程中,但是已经可以提前暴露了(比如已经被提取了对象工厂放入了三级缓存),那么这个Bean的早期引用就会放入这里。 3. 第三级缓存三级缓存):是一个名为`singletonFactories`的Map,用于存放Bean工厂对象,即ObjectFactory。这个缓存存放的是可以生成Bean实例的工厂对象,主要是用于解决循环依赖问题。当创建一个Bean时,如果发现该Bean依赖于另一个还未创建的Bean,就会创建一个工厂对象放入三级缓存,通过这个工厂对象可以提前暴露一个创建中的Bean的引用,从而解决循环依赖的问题。 在Spring创建Bean的过程中,会首先尝试从一级缓存中获取Bean,如果获取不到,会去二级缓存中查找,如果二级缓存也没有,再看三级缓存中是否有对应的工厂对象。如果有,就通过工厂对象创建Bean,然后放入二级缓存,并且从三级缓存中移除对应的工厂对象。最终,完全初始化后的Bean会放入一级缓存。 这种三级缓存的设计允许Spring在创建Bean的过程中,通过提前暴露工厂对象,解决了循环依赖的问题,保证了Bean的创建和初始化能够顺利进行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值