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