UnrefedBitmapCache.java revision 93a35b93dc582e38ff8ee5979754a16b4bf4da0c
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.bitmap; 18 19import android.util.Log; 20import android.util.LruCache; 21 22import com.android.bitmap.DecodeTask.Request; 23import com.android.bitmap.ReusableBitmap.NullReusableBitmap; 24import com.android.bitmap.util.Trace; 25 26/** 27 * This subclass provides custom pool behavior. The pool can be set to block on {@link #poll()} if 28 * nothing can be returned. This is useful if you know you will incur high costs upon receiving 29 * nothing from the pool, and you do not want to incur those costs at the critical moment when the 30 * UI is animating. 31 * 32 * This subclass provides custom cache behavior. Null values can be cached. Later, 33 * when the same key is used to retrieve the value, a {@link NullReusableBitmap} singleton will 34 * be returned. 35 */ 36public class UnrefedBitmapCache extends UnrefedPooledCache<Request, ReusableBitmap> 37 implements BitmapCache { 38 private boolean mBlocking = false; 39 private final Object mLock = new Object(); 40 41 private LruCache<Request, NullReusableBitmap> mNullRequests; 42 43 private final static boolean DEBUG = false; 44 private final static String TAG = UnrefedBitmapCache.class.getSimpleName(); 45 46 public UnrefedBitmapCache(final int targetSizeBytes, final float nonPooledFraction, 47 final int nullCapacity) { 48 super(targetSizeBytes, nonPooledFraction); 49 50 if (nullCapacity > 0) { 51 mNullRequests = new LruCache<Request, NullReusableBitmap>(nullCapacity); 52 } 53 } 54 55 /** 56 * Declare that {@link #poll()} should now block until it can return something. 57 */ 58 @Override 59 public void setBlocking(final boolean blocking) { 60 synchronized (mLock) { 61 if (DEBUG) { 62 Log.d(TAG, String.format("AltBitmapCache: block %b", blocking)); 63 } 64 mBlocking = blocking; 65 if (!mBlocking) { 66 // no longer blocking. Notify every thread. 67 mLock.notifyAll(); 68 } 69 } 70 } 71 72 @Override 73 protected int sizeOf(final ReusableBitmap value) { 74 return value.getByteCount(); 75 } 76 77 /** 78 * If {@link #setBlocking(boolean)} has been called with true, this method will block until a 79 * resource is available. 80 * @return an available resource, or null if none are available. Null will never be returned 81 * until blocking is set to false. 82 */ 83 @Override 84 public ReusableBitmap poll() { 85 ReusableBitmap bitmap; 86 synchronized (mLock) { 87 while ((bitmap = super.poll()) == null && mBlocking) { 88 if (DEBUG) { 89 Log.d(TAG, String.format( 90 "AltBitmapCache: %s waiting", Thread.currentThread().getName())); 91 } 92 Trace.beginSection("sleep"); 93 try { 94 // block 95 mLock.wait(); 96 if (DEBUG) { 97 Log.d(TAG, String.format("AltBitmapCache: %s notified", 98 Thread.currentThread().getName())); 99 } 100 } catch (InterruptedException ignored) { 101 } 102 Trace.endSection(); 103 } 104 } 105 return bitmap; 106 } 107 108 @Override 109 public void offer(final ReusableBitmap value) { 110 synchronized (mLock) { 111 super.offer(value); 112 if (DEBUG) { 113 Log.d(TAG, "AltBitmapCache: offer +1"); 114 } 115 // new resource gained. Notify one thread. 116 mLock.notify(); 117 } 118 } 119 120 @Override 121 public ReusableBitmap get(final Request key, final boolean incrementRefCount) { 122 if (mNullRequests != null && mNullRequests.get(key) != null) { 123 return NullReusableBitmap.getInstance(); 124 } 125 return super.get(key, incrementRefCount); 126 } 127 128 /** 129 * Note: The cache only supports same-sized bitmaps. 130 */ 131 @Override 132 public ReusableBitmap put(final Request key, final ReusableBitmap value) { 133 if (mNullRequests != null && (value == null || value == NullReusableBitmap.getInstance())) { 134 mNullRequests.put(key, NullReusableBitmap.getInstance()); 135 return null; 136 } 137 138 return super.put(key, value); 139 } 140} 141