美文网首页
LruCache源码分析

LruCache源码分析

作者: wervy | 来源:发表于2020-01-21 10:08 被阅读0次

在Android中常用的缓存策略是LruCache和DiskLruCache
其中LruCache常被用作内存缓存。Lru是Least Recently Used的缩写

核心思想是:当缓存快满的时候,会移除较早使用的缓存对象,然后添加新的缓存对象

我们平常在项目中如果需要用到缓存,一般都是这么使用的

private TextView text2;
    private ImageView imageView;
    private LruCache<String,Bitmap> mCaChe;

    private Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_touch_dispatch);
        initCaChe();
        initView();
    }



    private void initView(){

        text2 = findViewById(R.id.text);
        imageView = findViewById(R.id.image);
        String str = "https://goss.veer.com/creative/vcg/veer/800water/veer-170484153.jpg";

        text2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Bitmap bitmap = getCacheImage("bitmap");
                if (bitmap == null){
                    loadImage();
                }else {
                    imageView.setImageBitmap(bitmap);
                }
            }
        });
    }


    private void initCaChe(){
       long maxMemory = Runtime.getRuntime().maxMemory()/1024;
        int cacheSize = (int) (maxMemory / 8);
        mCaChe = new LruCache<String,Bitmap>(cacheSize){

            //重写sizeof方法,计算出要缓存的每张图片的大小
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight()/1024;
            }
        };
    }

    /**
     * 读取缓存中Bitmap
     * @param key
     * @return
     */
    private Bitmap getCacheImage(String key){

        Bitmap bitmap = mCaChe.get(key);
        return bitmap;
    }

    private void removeCache(String key){

        mCaChe.remove(key);
    }

    /**
     * 添加缓存
     * @param key
     * @param bitmap
     */
    private void addCache(String key, Bitmap bitmap){

        if (getCacheImage(key) == null){
            mCaChe.put(key,bitmap);
        }
    }

    private void loadImage(){
        String str = "http://5b0988e595225.cdn.sohucs.com/images/20171210/362dcd1c009842ff99b33f5d51bbfb80.jpeg";


        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder().url(str).get().build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                final byte[] picture = response.body().bytes();

                handler.post(new Runnable() {
                    @Override
                    public void run() {

                        Bitmap bitmap = BitmapFactory.decodeByteArray(picture,0,picture.length);
                        addCache("bitmap",bitmap);
                        imageView.setImageBitmap(bitmap);

                    }
                });
            }
        });
    }

我们来看一下LruCache的源码:

/**
     * @param maxSize for caches that do not override {@link #sizeOf}, this is
     *     the maximum number of entries in the cache. For all other caches,
     *     this is the maximum sum of the sizes of the entries in this cache.
     */
    public LruCache(int maxSize) {
        if (maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        }
        this.maxSize = maxSize;
        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
    }

由构造方法可以看出,LruCache内部采用的是LinkedHashMap

添加数据的put方法

 /**
     * Caches {@code value} for {@code key}. The value is moved to the head of
     * the queue.
     *
     * @return the previous value mapped by {@code key}.
     */
    public final V put(K key, V value) {
        if (key == null || value == null) {
            throw new NullPointerException("key == null || value == null");
        }

        V previous;
        synchronized (this) {
            putCount++;
            size += safeSizeOf(key, value);
            previous = map.put(key, value);
            if (previous != null) {
                size -= safeSizeOf(key, previous);
            }
        }

        if (previous != null) {
            entryRemoved(false, key, previous, value);
        }

        trimToSize(maxSize);
        return previous;
    }

这段代码就是把key/value键值对,放入map中,并扩充每次图片的大小,size增加,如果map中存在这个key,则size减去之前图片的大小

获取数据的get方法

/**
     * Returns the value for {@code key} if it exists in the cache or can be
     * created by {@code #create}. If a value was returned, it is moved to the
     * head of the queue. This returns null if a value is not cached and cannot
     * be created.
     */
    public final V get(K key) {
        if (key == null) {
            throw new NullPointerException("key == null");
        }

        V mapValue;
        synchronized (this) {
            mapValue = map.get(key);
            if (mapValue != null) {
                hitCount++;
                return mapValue;
            }
            missCount++;
        }

        /*
         * Attempt to create a value. This may take a long time, and the map
         * may be different when create() returns. If a conflicting value was
         * added to the map while create() was working, we leave that value in
         * the map and release the created value.
         */

        V createdValue = create(key);
        if (createdValue == null) {
            return null;
        }

        synchronized (this) {
            createCount++;
            mapValue = map.put(key, createdValue);

            if (mapValue != null) {
                // There was a conflict so undo that last put
                map.put(key, mapValue);
            } else {
                size += safeSizeOf(key, createdValue);
            }
        }

        if (mapValue != null) {
            entryRemoved(false, key, createdValue, mapValue);
            return mapValue;
        } else {
            trimToSize(maxSize);
            return createdValue;
        }
    }

当调用LruCache的get()方法获取集合中的缓存对象时,就代表访问了一次该元素,将会更新队列,保持整个队列是按照访问顺序排序,这个更新过程就是在LinkedHashMap中的get()方法中完成的。

综上所述

LruCache主要是内置了LinkedHash。它的最近最少使用原则也是通过LinkedHashMap来实现的。
我们接下来看一下LinkedHashMap这个类
LinkedHashMap是HashMap的子类,但是内部还有一个双向链表维护键值对的顺序,每个键值对即位于哈希表中,也位于双向链表中,LinkedHashMap支持两种顺序

插入顺序 访问顺序

  • 插入顺序:先添加的在前面,后添加的在后面,修改操作不影响顺序
    *访问顺序:对一个健执行get/put操作后,其对应的键值会移到链表末尾
    我们在代码中测试一下:
public class TestLinkedHashMap {

    public static void main(String[] args){

        //插入顺序
        Map<String,String> map = new LinkedHashMap<>();
        map.put("1","abc");
        map.put("2","cde");
        map.put("3","dddd");
        map.put("4","44444");
        map.get("2");
        map.put("2","2222");
        System.out.println(map.toString());

        //访问顺序
        Map<String,String> linkedHashMap = new LinkedHashMap(16,0.75f,true);
        linkedHashMap.put("1","abc");
        linkedHashMap.put("2","cde");
        linkedHashMap.put("3","dddd");
        linkedHashMap.put("4","44444");
        linkedHashMap.get("2");
        linkedHashMap.put("2","2222");
        System.out.println(linkedHashMap.toString());
    }
}

运行结果如下:


image.png

可以看到在访问顺序的请款下:最近访问修改的,移到了末尾

相关文章

  • Android-Glide源码解析

    一、LruCache 要分析Glide的源码,首先就需要分析LruCache。LruCache是基于LinkedH...

  • LruCache之LruCache分析

    LruCache 分析 LruCache 是 Android 的一个内部类,提供了基于内存实现的缓存 用法 源码 ...

  • LruCache

    文章主要介绍了:1.LruCache的基本使用2.LruCache的源码分析3.基于LinkedHashMap的实...

  • LruCache源码分析

    LruCache类里面有一个LinkedHashMap map的变量,缓存主要就是用这个map来做的,l...

  • 源码分析 LruCache

    简介 为什么用 一个app持有的内存是有限的,无限制的使用强引用在内存中缓存数据,有可能导致OOM。 能做什么 L...

  • LruCache源码分析

    在开发中我们会经常碰到一些资源需要做缓存优化,例如Bitmap,Json等,那么今天我们来瞧瞧默默无闻的LruCa...

  • LruCache源码分析

    LruCache的原理 LruCache主要靠LinkedHashMap的一个按访问排序的特性实现的,Linked...

  • LruCache源码分析

    LruCache的源码分析已经很多了,看了很多遍,但是自己走一遍分析,才是真正的掌握,将知识转化到自身。 用途 L...

  • LruCache源码分析

    LruCache的源码分析已经很多了,看了很多遍,但是自己走一遍分析,才是真正的掌握,将知识转化到自身。 用途 L...

  • LruCache源码分析

    对于LruCache的分析,我们可以从官方介绍开始,直接把源码中的注释拿过来。 A cache that hold...

网友评论

      本文标题:LruCache源码分析

      本文链接:https://www.haomeiwen.com/subject/cmmoactx.html