UnrefedBitmapCache.java revision 93a35b93dc582e38ff8ee5979754a16b4bf4da0c
193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/*
293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Copyright (C) 2013 The Android Open Source Project
393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Licensed under the Apache License, Version 2.0 (the "License");
593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * you may not use this file except in compliance with the License.
693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * You may obtain a copy of the License at
793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *      http://www.apache.org/licenses/LICENSE-2.0
993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
1093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Unless required by applicable law or agreed to in writing, software
1193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * distributed under the License is distributed on an "AS IS" BASIS,
1293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * See the License for the specific language governing permissions and
1493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * limitations under the License.
1593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */
1693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
1793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpackage com.android.bitmap;
1893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
1993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.util.Log;
2093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.util.LruCache;
2193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
2293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.DecodeTask.Request;
2393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.ReusableBitmap.NullReusableBitmap;
2493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.Trace;
2593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
2693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/**
2793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * This subclass provides custom pool behavior. The pool can be set to block on {@link #poll()} if
2893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * nothing can be returned. This is useful if you know you will incur high costs upon receiving
2993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * nothing from the pool, and you do not want to incur those costs at the critical moment when the
3093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * UI is animating.
3193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
3293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * This subclass provides custom cache behavior. Null values can be cached. Later,
3393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * when the same key is used to retrieve the value, a {@link NullReusableBitmap} singleton will
3493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * be returned.
3593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */
3693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpublic class UnrefedBitmapCache extends UnrefedPooledCache<Request, ReusableBitmap>
3793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        implements BitmapCache {
3893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private boolean mBlocking = false;
3993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final Object mLock = new Object();
4093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
4193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private LruCache<Request, NullReusableBitmap> mNullRequests;
4293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
4393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final static boolean DEBUG = false;
4493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final static String TAG = UnrefedBitmapCache.class.getSimpleName();
4593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
4693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public UnrefedBitmapCache(final int targetSizeBytes, final float nonPooledFraction,
4793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            final int nullCapacity) {
4893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        super(targetSizeBytes, nonPooledFraction);
4993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
5093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (nullCapacity > 0) {
5193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mNullRequests = new LruCache<Request, NullReusableBitmap>(nullCapacity);
5293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
5393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
5493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
5593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    /**
5693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * Declare that {@link #poll()} should now block until it can return something.
5793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     */
5893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
5993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void setBlocking(final boolean blocking) {
6093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        synchronized (mLock) {
6193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (DEBUG) {
6293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                Log.d(TAG, String.format("AltBitmapCache: block %b", blocking));
6393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
6493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mBlocking = blocking;
6593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (!mBlocking) {
6693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                // no longer blocking. Notify every thread.
6793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                mLock.notifyAll();
6893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
6993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
7093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
7193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
7293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
7393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    protected int sizeOf(final ReusableBitmap value) {
7493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return value.getByteCount();
7593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
7693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
7793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    /**
7893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * If {@link #setBlocking(boolean)} has been called with true, this method will block until a
7993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * resource is available.
8093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * @return an available resource, or null if none are available. Null will never be returned
8193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * until blocking is set to false.
8293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     */
8393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
8493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public ReusableBitmap poll() {
8593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        ReusableBitmap bitmap;
8693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        synchronized (mLock) {
8793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            while ((bitmap = super.poll()) == null && mBlocking) {
8893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (DEBUG) {
8993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    Log.d(TAG, String.format(
9093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                            "AltBitmapCache: %s waiting", Thread.currentThread().getName()));
9193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
9293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                Trace.beginSection("sleep");
9393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                try {
9493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    // block
9593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    mLock.wait();
9693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    if (DEBUG) {
9793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        Log.d(TAG, String.format("AltBitmapCache: %s notified",
9893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                                Thread.currentThread().getName()));
9993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    }
10093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                } catch (InterruptedException ignored) {
10193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
10293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                Trace.endSection();
10393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
10493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
10593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return bitmap;
10693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
10793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
10893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
10993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void offer(final ReusableBitmap value) {
11093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        synchronized (mLock) {
11193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            super.offer(value);
11293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (DEBUG) {
11393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                Log.d(TAG, "AltBitmapCache: offer +1");
11493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
11593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            // new resource gained. Notify one thread.
11693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mLock.notify();
11793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
11893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
11993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
12093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
12193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public ReusableBitmap get(final Request key, final boolean incrementRefCount) {
12293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (mNullRequests != null && mNullRequests.get(key) != null) {
12393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            return NullReusableBitmap.getInstance();
12493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
12593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return super.get(key, incrementRefCount);
12693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
12793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
12893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    /**
12993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * Note: The cache only supports same-sized bitmaps.
13093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     */
13193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
13293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public ReusableBitmap put(final Request key, final ReusableBitmap value) {
13393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (mNullRequests != null && (value == null || value == NullReusableBitmap.getInstance())) {
13493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mNullRequests.put(key, NullReusableBitmap.getInstance());
13593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            return null;
13693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
13793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
13893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return super.put(key, value);
13993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
14093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein}
141