diff options
Diffstat (limited to 'src/com/android/bitmap/UnrefedBitmapCache.java')
-rw-r--r-- | src/com/android/bitmap/UnrefedBitmapCache.java | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/src/com/android/bitmap/UnrefedBitmapCache.java b/src/com/android/bitmap/UnrefedBitmapCache.java new file mode 100644 index 0000000..6c9db73 --- /dev/null +++ b/src/com/android/bitmap/UnrefedBitmapCache.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.bitmap; + +import android.util.Log; +import android.util.LruCache; + +import com.android.bitmap.DecodeTask.Request; +import com.android.bitmap.ReusableBitmap.NullReusableBitmap; +import com.android.bitmap.util.Trace; + +/** + * This subclass provides custom pool behavior. The pool can be set to block on {@link #poll()} if + * nothing can be returned. This is useful if you know you will incur high costs upon receiving + * nothing from the pool, and you do not want to incur those costs at the critical moment when the + * UI is animating. + * + * This subclass provides custom cache behavior. Null values can be cached. Later, + * when the same key is used to retrieve the value, a {@link NullReusableBitmap} singleton will + * be returned. + */ +public class UnrefedBitmapCache extends UnrefedPooledCache<Request, ReusableBitmap> + implements BitmapCache { + private boolean mBlocking = false; + private final Object mLock = new Object(); + + private LruCache<Request, NullReusableBitmap> mNullRequests; + + private final static boolean DEBUG = false; + private final static String TAG = UnrefedBitmapCache.class.getSimpleName(); + + public UnrefedBitmapCache(final int targetSizeBytes, final float nonPooledFraction, + final int nullCapacity) { + super(targetSizeBytes, nonPooledFraction); + + if (nullCapacity > 0) { + mNullRequests = new LruCache<Request, NullReusableBitmap>(nullCapacity); + } + } + + /** + * Declare that {@link #poll()} should now block until it can return something. + */ + @Override + public void setBlocking(final boolean blocking) { + synchronized (mLock) { + if (DEBUG) { + Log.d(TAG, String.format("AltBitmapCache: block %b", blocking)); + } + mBlocking = blocking; + if (!mBlocking) { + // no longer blocking. Notify every thread. + mLock.notifyAll(); + } + } + } + + @Override + protected int sizeOf(final ReusableBitmap value) { + return value.getByteCount(); + } + + /** + * If {@link #setBlocking(boolean)} has been called with true, this method will block until a + * resource is available. + * @return an available resource, or null if none are available. Null will never be returned + * until blocking is set to false. + */ + @Override + public ReusableBitmap poll() { + ReusableBitmap bitmap; + synchronized (mLock) { + while ((bitmap = super.poll()) == null && mBlocking) { + if (DEBUG) { + Log.d(TAG, String.format( + "AltBitmapCache: %s waiting", Thread.currentThread().getName())); + } + Trace.beginSection("sleep"); + try { + // block + mLock.wait(); + if (DEBUG) { + Log.d(TAG, String.format("AltBitmapCache: %s notified", + Thread.currentThread().getName())); + } + } catch (InterruptedException ignored) { + } + Trace.endSection(); + } + } + return bitmap; + } + + @Override + public void offer(final ReusableBitmap value) { + synchronized (mLock) { + super.offer(value); + if (DEBUG) { + Log.d(TAG, "AltBitmapCache: offer +1"); + } + // new resource gained. Notify one thread. + mLock.notify(); + } + } + + @Override + public ReusableBitmap get(final Request key, final boolean incrementRefCount) { + if (mNullRequests != null && mNullRequests.get(key) != null) { + return NullReusableBitmap.getInstance(); + } + return super.get(key, incrementRefCount); + } + + /** + * Note: The cache only supports same-sized bitmaps. + */ + @Override + public ReusableBitmap put(final Request key, final ReusableBitmap value) { + if (mNullRequests != null && (value == null || value == NullReusableBitmap.getInstance())) { + mNullRequests.put(key, NullReusableBitmap.getInstance()); + return null; + } + + return super.put(key, value); + } +} |