android pdf框架-8,图片缓存

解码会产生很多图片,滑过后不要显示,如果直接回收,会浪费不少资源.

在没有缓存的情况下,会看到gc还是比较频繁的.

有了缓存后,明显gc少了.

目录

常用的缓存

自定义缓存

显示相关的内存缓存

解码缓存池

内存缓存实现:

解码缓存池实现:


常用的缓存

lrucache,这是最常用的,也是android sdk里面有的.就是按访问时间顺序,内部使用linkedhashmap,会记录访问时间.

androidx.core.util.Pools

这是一个接口,实现后可以自己管理池.严格来说,它并不是一个缓存类,是用来构建缓存的基础类.

用lrucache作缓存,有一些不好的点,设置了容量并不是图片的字节总数,是图片的张数.这对于图片大小不一的情况,可能并不是很好.

自定义缓存
显示相关的内存缓存

需要string作缓存key,能读取,且能根据容量把最早未访问的清除出缓存队列.

解码缓存池

当需要解码时,从池里面找到bitmap,对于高版本的系统,解码可以使用比当前高宽大的图片来处理.那么当图片从上面的内存缓存中清除,不是调用recycle(),而是将它放入解码缓存池.这对于解码来说,会明显减少gc.

内存缓存实现:

既然lru这么好用,就参与它,把源码拿来修改下.有了自动清除最早访问的位图功能,又有根据总字节数去管理缓存.

private static final int mMaxPoolSizeInBytes = 100 * 1024 * 1024;

    private int mPoolSizeInBytes = 0;
定义了最大缓存100m, 这个值可以根据系统内存大小去调整,这里先固定.
private final LinkedHashMap map = new LinkedHashMap<>(16, 0.75f, true);
默认先设16
获取图片,不需要去创建,如果为空就返回空.这与lru不一样的.
public final Bitmap getBitmap(@NonNull String key) {
        if (key == null) {
            throw new NullPointerException("key == null");
        }

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

        return null;
    }

//添加图片,
public final Bitmap addBitmap(@NonNull String key, @NonNull Bitmap value) {
        if (key == null || value == null) {
            throw new NullPointerException("key == null || value == null");
        }
//添加前先判断是否总容量已经达到限定的值,如果是就清除,直到总容量符合要求,然后再添加.如果总容量设置很小,那么这里的效率会比较低.
        while (mPoolSizeInBytes > mMaxPoolSizeInBytes) {
            removeLast();
        }

        mPoolSizeInBytes += value.getByteCount();

        Bitmap previous;
        synchronized (this) {
            putCount++;
            previous = map.put(key, value);
            if (previous != null) { //对于移除的要把容量减去它的大小.
                mPoolSizeInBytes -= previous.getByteCount();
            }
        }
        //System.out.println(String.format("put.size:%s, key:%s, val:%s, size:%s", map.size(), key, value, mPoolSizeInBytes));

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

        return previous;
    }

//与lrucache差不多,记得容量的计算
private void removeLast() {
        String key;
        Bitmap value;
        synchronized (this) {
            if (map.isEmpty()) {
                return;
            }

            Map.Entry toEvict = map.entrySet().iterator().next();
            key = toEvict.getKey();
            value = toEvict.getValue();
            map.remove(key);
            mPoolSizeInBytes -= value.getByteCount();
            evictionCount++;
        }
        //System.out.println(String.format("removeLast.size:%s, key:%s,val:%s, size:%s", map.size(), key, value, mPoolSizeInBytes));

        entryRemoved(true, key, value, null);
    }

public final Bitmap remove(@NonNull String key) {
        if (key == null) {
            throw new NullPointerException("key == null");
        }

        Bitmap previous;
        synchronized (this) {
            previous = map.remove(key);
            if (previous != null) {
                mPoolSizeInBytes -= previous.getByteCount();
            }
        }

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

        return previous;
    }

当关闭页面时,建议清除所有的数据
public final void clear() {
        int size = map.size();
        for (int i = 0; i < size; i++) {
            removeLast();
        }
    }

这是内存缓存类,可以设置为单例.

解码缓存池实现:

BitmapPool,也设置单例.

public static class FixedSimplePool implements Pools.Pool {
        private final Object[] mPool;

        private int mPoolSize;

        /**
         * Creates a new instance.
         *
         * @param maxPoolSize The max pool size.
         * @throws IllegalArgumentException If the max pool size is less than zero.
         */
        public FixedSimplePool(int maxPoolSize) {
            if (maxPoolSize <= 0) {
                throw new IllegalArgumentException("The max pool size must be > 0");
            }
            mPool = new Object[maxPoolSize];
        }

        @Override
        @SuppressWarnings("unchecked")
        public T acquire() {
            if (mPoolSize > 0) {
                final int lastPooledIndex = mPoolSize - 1;
                T instance = (T) mPool[lastPooledIndex];
                mPool[lastPooledIndex] = null;
                mPoolSize--;
                return instance;
            }
            return null;
        }

        @Override
        public boolean release(@NonNull T instance) {
            if (isInPool(instance)) {
                return false;
            }
            if (mPoolSize < mPool.length) {
                mPool[mPoolSize] = instance;
                mPoolSize++;
                return true;
            }
            return false;
        }

        private boolean isInPool(@NonNull T instance) {
            for (int i = 0; i < mPoolSize; i++) {
                if (mPool[i] == instance) {
                    return true;
                }
            }
            return false;
        }
    }

这段代码好像是sdk里面有的.忘了是不是了.就是实现了 pools接口,然后用数组去存储数据

整个pool向外提供两个方法,aquried,release.

public Bitmap acquire(int width, int height) {
        Bitmap b = simplePool.acquire();
        if (null == b) {
            b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        } else {
            if (b.getHeight() == height && b.getWidth() == width) {
                //Log.d("TAG", String.format("use cache:%s-%s-%s%n", width, height, simplePool.mPoolSize));
                b.eraseColor(0);
            } else {
                b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            }
        }
        return b;
    }

    public void release(Bitmap bitmap) {
        boolean isRelease = simplePool.release(bitmap);
        if (!isRelease) {
            System.out.println("recycle bitmap:" + bitmap);
            bitmap.recycle();
        }
    }

解码时的bitmap从这个单例里面取.而不是新建

val bm = BitmapPool.getInstance().acquire(width, height)

// val page = mupdfDocument?.loadPage(pageSize.index) ?: return null

至于什么时候release对象,这需要在确定不用bitmap时,把它加入到BitmapPool中.

你可能感兴趣的:(pdf,pdf,android)