com.facebook.litho.reference.DrawableResourcesCache.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.litho.reference.DrawableResourcesCache.java

Source

/**
 * Copyright (c) 2017-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

package com.facebook.litho.reference;

import java.util.concurrent.atomic.AtomicInteger;

import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.util.LruCache;
import android.support.v4.util.Pools;
import android.util.StateSet;

import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.HONEYCOMB;

/**
 * A cache that holds Drawables retreived from Android {@link android.content.res.Resources} for
 * each resId this class keeps a {@link android.support.v4.util.Pools.SynchronizedPool} of
 * DRAWABLES_POOL_MAX_ITEMS. The cache has a maximum capacity of DRAWABLES_MAX_ENTRIES. When the
 * cache is full it starts clearing memory deleting the less recently used pool of resources
 */
class DrawableResourcesCache {

    private static final int DRAWABLES_MAX_ENTRIES = 200;
    private static final int DRAWABLES_POOL_MAX_ITEMS = 10;

    private final LruCache<Integer, SimplePoolWithCount<Drawable>> mDrawableCache;

    DrawableResourcesCache() {
        mDrawableCache = new LruCache<Integer, SimplePoolWithCount<Drawable>>(DRAWABLES_MAX_ENTRIES) {
            @Override
            protected int sizeOf(Integer key, SimplePoolWithCount<Drawable> value) {
                return value.getPoolSize();
            }
        };
    }

    /**
     * @deprecated use {@link #get(int, Resources, Resources.Theme)}
     */
    @Deprecated
    public @Nullable Drawable get(int resId, Resources resources) {
        return get(resId, resources, null);
    }

    public @Nullable Drawable get(int resId, Resources resources, @Nullable Resources.Theme theme) {
        SimplePoolWithCount<Drawable> drawablesPool = mDrawableCache.get(resId);

        if (drawablesPool == null) {
            drawablesPool = new SimplePoolWithCount<>(DRAWABLES_POOL_MAX_ITEMS);
            mDrawableCache.put(resId, drawablesPool);
        }

        Drawable drawable = drawablesPool.acquire();

        if (drawable == null) {
            drawable = ResourcesCompat.getDrawable(resources, resId, theme);
        }

        // We never want this pool to remain empty otherwise we would risk to resolve a new drawable
        // when get is called again. So if the pool is about to drain we just put a new Drawable in it
        // to keep it warm.
        if (drawable != null && drawablesPool.getPoolSize() == 0) {
            drawablesPool.release(drawable.getConstantState().newDrawable());
        }

        return drawable;
    }

    public void release(Drawable drawable, int resId) {
        SimplePoolWithCount<Drawable> drawablesPool = mDrawableCache.get(resId);
        if (drawablesPool == null) {
            drawablesPool = new SimplePoolWithCount<>(DRAWABLES_POOL_MAX_ITEMS);
            mDrawableCache.put(resId, drawablesPool);
        }

        // Reset a stateful drawable, and its animations, before being released.
        if (drawable.isStateful()) {
            drawable.setState(StateSet.WILD_CARD);

            if (SDK_INT >= HONEYCOMB) {
                drawable.jumpToCurrentState();
            }
        }

        drawablesPool.release(drawable);
    }

    private static class SimplePoolWithCount<T> extends Pools.SynchronizedPool<T> {

        private AtomicInteger mPoolSize;

        public SimplePoolWithCount(int maxPoolSize) {
            super(maxPoolSize);
            mPoolSize = new AtomicInteger(0);
        }

        @Override
        public T acquire() {
            T item = super.acquire();
            if (item != null) {
                mPoolSize.decrementAndGet();
            }

            return item;
        }

        @Override
        public boolean release(T instance) {
            boolean added = super.release(instance);
            if (added) {
                mPoolSize.incrementAndGet();
            }

            return added;
        }

        public int getPoolSize() {
            return mPoolSize.get();
        }
    }
}