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.ReusableBitmap.NullReusableBitmap; 2393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.Trace; 2493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 2593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/** 2693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * This subclass provides custom pool behavior. The pool can be set to block on {@link #poll()} if 2793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * nothing can be returned. This is useful if you know you will incur high costs upon receiving 2893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * nothing from the pool, and you do not want to incur those costs at the critical moment when the 2993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * UI is animating. 3093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * 3193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * This subclass provides custom cache behavior. Null values can be cached. Later, 3293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * when the same key is used to retrieve the value, a {@link NullReusableBitmap} singleton will 3393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * be returned. 3493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 3540662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzsteinpublic class UnrefedBitmapCache extends UnrefedPooledCache<RequestKey, ReusableBitmap> 3693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein implements BitmapCache { 3793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private boolean mBlocking = false; 3893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private final Object mLock = new Object(); 3993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 4040662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein private LruCache<RequestKey, NullReusableBitmap> mNullRequests; 4193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 42cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei private final static boolean DEBUG = DecodeTask.DEBUG; 4393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein private final static String TAG = UnrefedBitmapCache.class.getSimpleName(); 4493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 4593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public UnrefedBitmapCache(final int targetSizeBytes, final float nonPooledFraction, 4693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein final int nullCapacity) { 4793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein super(targetSizeBytes, nonPooledFraction); 4893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 4993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (nullCapacity > 0) { 5040662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein mNullRequests = new LruCache<RequestKey, NullReusableBitmap>(nullCapacity); 5193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 5293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 5393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 5493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 5593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Declare that {@link #poll()} should now block until it can return something. 5693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 5793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 5893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void setBlocking(final boolean blocking) { 5993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein synchronized (mLock) { 6093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (DEBUG) { 6193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.d(TAG, String.format("AltBitmapCache: block %b", blocking)); 6293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 6393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mBlocking = blocking; 6493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (!mBlocking) { 6593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // no longer blocking. Notify every thread. 6693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mLock.notifyAll(); 6793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 6893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 6993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 7093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 7193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 7293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein protected int sizeOf(final ReusableBitmap value) { 7393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return value.getByteCount(); 7493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 7593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 7693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 7793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * If {@link #setBlocking(boolean)} has been called with true, this method will block until a 7893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * resource is available. 7993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * @return an available resource, or null if none are available. Null will never be returned 8093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * until blocking is set to false. 8193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 8293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 8393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public ReusableBitmap poll() { 8493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein ReusableBitmap bitmap; 8593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein synchronized (mLock) { 8693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein while ((bitmap = super.poll()) == null && mBlocking) { 8793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (DEBUG) { 8893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.d(TAG, String.format( 8993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein "AltBitmapCache: %s waiting", Thread.currentThread().getName())); 9093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 9193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.beginSection("sleep"); 9293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein try { 9393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // block 9493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mLock.wait(); 9593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (DEBUG) { 9693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.d(TAG, String.format("AltBitmapCache: %s notified", 9793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Thread.currentThread().getName())); 9893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 9993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } catch (InterruptedException ignored) { 10093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 10193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Trace.endSection(); 10293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 10393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 10493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return bitmap; 10593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 10693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 10793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 10893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein public void offer(final ReusableBitmap value) { 10993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein synchronized (mLock) { 11093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein super.offer(value); 11193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (DEBUG) { 11293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein Log.d(TAG, "AltBitmapCache: offer +1"); 11393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 11493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein // new resource gained. Notify one thread. 11593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mLock.notify(); 11693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 11793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 11893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 11993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 12040662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein public ReusableBitmap get(final RequestKey key, final boolean incrementRefCount) { 12193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mNullRequests != null && mNullRequests.get(key) != null) { 12293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return NullReusableBitmap.getInstance(); 12393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 12493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return super.get(key, incrementRefCount); 12593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 12693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 12793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein /** 12893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Note: The cache only supports same-sized bitmaps. 12993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */ 13093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein @Override 13140662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein public ReusableBitmap put(final RequestKey key, final ReusableBitmap value) { 13293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein if (mNullRequests != null && (value == null || value == NullReusableBitmap.getInstance())) { 13393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein mNullRequests.put(key, NullReusableBitmap.getInstance()); 13493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return null; 13593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 13693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein 13793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein return super.put(key, value); 13893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein } 13993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein} 140