1 /* 2 * Copyright (C) 2012 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 17 package com.example.android.bitmapfun.util; 18 19 import android.content.Context; 20 import android.graphics.Bitmap; 21 import android.graphics.Bitmap.CompressFormat; 22 import android.support.v4.app.FragmentActivity; 23 import android.support.v4.util.LruCache; 24 import android.util.Log; 25 26 import com.example.android.bitmapfun.BuildConfig; 27 28 import java.io.File; 29 30 /** 31 * This class holds our bitmap caches (memory and disk). 32 */ 33 public class ImageCache { 34 private static final String TAG = "ImageCache"; 35 36 // Default memory cache size 37 private static final int DEFAULT_MEM_CACHE_SIZE = 1024 * 1024 * 5; // 5MB 38 39 // Default disk cache size 40 private static final int DEFAULT_DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB 41 42 // Compression settings when writing images to disk cache 43 private static final CompressFormat DEFAULT_COMPRESS_FORMAT = CompressFormat.JPEG; 44 private static final int DEFAULT_COMPRESS_QUALITY = 70; 45 46 // Constants to easily toggle various caches 47 private static final boolean DEFAULT_MEM_CACHE_ENABLED = true; 48 private static final boolean DEFAULT_DISK_CACHE_ENABLED = true; 49 private static final boolean DEFAULT_CLEAR_DISK_CACHE_ON_START = false; 50 51 private DiskLruCache mDiskCache; 52 private LruCache<String, Bitmap> mMemoryCache; 53 54 /** 55 * Creating a new ImageCache object using the specified parameters. 56 * 57 * @param context The context to use 58 * @param cacheParams The cache parameters to use to initialize the cache 59 */ ImageCache(Context context, ImageCacheParams cacheParams)60 public ImageCache(Context context, ImageCacheParams cacheParams) { 61 init(context, cacheParams); 62 } 63 64 /** 65 * Creating a new ImageCache object using the default parameters. 66 * 67 * @param context The context to use 68 * @param uniqueName A unique name that will be appended to the cache directory 69 */ ImageCache(Context context, String uniqueName)70 public ImageCache(Context context, String uniqueName) { 71 init(context, new ImageCacheParams(uniqueName)); 72 } 73 74 /** 75 * Find and return an existing ImageCache stored in a {@link RetainFragment}, if not found a new 76 * one is created with defaults and saved to a {@link RetainFragment}. 77 * 78 * @param activity The calling {@link FragmentActivity} 79 * @param uniqueName A unique name to append to the cache directory 80 * @return An existing retained ImageCache object or a new one if one did not exist. 81 */ findOrCreateCache( final FragmentActivity activity, final String uniqueName)82 public static ImageCache findOrCreateCache( 83 final FragmentActivity activity, final String uniqueName) { 84 return findOrCreateCache(activity, new ImageCacheParams(uniqueName)); 85 } 86 87 /** 88 * Find and return an existing ImageCache stored in a {@link RetainFragment}, if not found a new 89 * one is created using the supplied params and saved to a {@link RetainFragment}. 90 * 91 * @param activity The calling {@link FragmentActivity} 92 * @param cacheParams The cache parameters to use if creating the ImageCache 93 * @return An existing retained ImageCache object or a new one if one did not exist 94 */ findOrCreateCache( final FragmentActivity activity, ImageCacheParams cacheParams)95 public static ImageCache findOrCreateCache( 96 final FragmentActivity activity, ImageCacheParams cacheParams) { 97 98 // Search for, or create an instance of the non-UI RetainFragment 99 final RetainFragment mRetainFragment = RetainFragment.findOrCreateRetainFragment( 100 activity.getSupportFragmentManager()); 101 102 // See if we already have an ImageCache stored in RetainFragment 103 ImageCache imageCache = (ImageCache) mRetainFragment.getObject(); 104 105 // No existing ImageCache, create one and store it in RetainFragment 106 if (imageCache == null) { 107 imageCache = new ImageCache(activity, cacheParams); 108 mRetainFragment.setObject(imageCache); 109 } 110 111 return imageCache; 112 } 113 114 /** 115 * Initialize the cache, providing all parameters. 116 * 117 * @param context The context to use 118 * @param cacheParams The cache parameters to initialize the cache 119 */ init(Context context, ImageCacheParams cacheParams)120 private void init(Context context, ImageCacheParams cacheParams) { 121 final File diskCacheDir = DiskLruCache.getDiskCacheDir(context, cacheParams.uniqueName); 122 123 // Set up disk cache 124 if (cacheParams.diskCacheEnabled) { 125 mDiskCache = DiskLruCache.openCache(context, diskCacheDir, cacheParams.diskCacheSize); 126 mDiskCache.setCompressParams(cacheParams.compressFormat, cacheParams.compressQuality); 127 if (cacheParams.clearDiskCacheOnStart) { 128 mDiskCache.clearCache(); 129 } 130 } 131 132 // Set up memory cache 133 if (cacheParams.memoryCacheEnabled) { 134 mMemoryCache = new LruCache<String, Bitmap>(cacheParams.memCacheSize) { 135 /** 136 * Measure item size in bytes rather than units which is more practical for a bitmap 137 * cache 138 */ 139 @Override 140 protected int sizeOf(String key, Bitmap bitmap) { 141 return Utils.getBitmapSize(bitmap); 142 } 143 }; 144 } 145 } 146 addBitmapToCache(String data, Bitmap bitmap)147 public void addBitmapToCache(String data, Bitmap bitmap) { 148 if (data == null || bitmap == null) { 149 return; 150 } 151 152 // Add to memory cache 153 if (mMemoryCache != null && mMemoryCache.get(data) == null) { 154 mMemoryCache.put(data, bitmap); 155 } 156 157 // Add to disk cache 158 if (mDiskCache != null && !mDiskCache.containsKey(data)) { 159 mDiskCache.put(data, bitmap); 160 } 161 } 162 163 /** 164 * Get from memory cache. 165 * 166 * @param data Unique identifier for which item to get 167 * @return The bitmap if found in cache, null otherwise 168 */ getBitmapFromMemCache(String data)169 public Bitmap getBitmapFromMemCache(String data) { 170 if (mMemoryCache != null) { 171 final Bitmap memBitmap = mMemoryCache.get(data); 172 if (memBitmap != null) { 173 if (BuildConfig.DEBUG) { 174 Log.d(TAG, "Memory cache hit"); 175 } 176 return memBitmap; 177 } 178 } 179 return null; 180 } 181 182 /** 183 * Get from disk cache. 184 * 185 * @param data Unique identifier for which item to get 186 * @return The bitmap if found in cache, null otherwise 187 */ getBitmapFromDiskCache(String data)188 public Bitmap getBitmapFromDiskCache(String data) { 189 if (mDiskCache != null) { 190 return mDiskCache.get(data); 191 } 192 return null; 193 } 194 clearCaches()195 public void clearCaches() { 196 mDiskCache.clearCache(); 197 mMemoryCache.evictAll(); 198 } 199 200 /** 201 * A holder class that contains cache parameters. 202 */ 203 public static class ImageCacheParams { 204 public String uniqueName; 205 public int memCacheSize = DEFAULT_MEM_CACHE_SIZE; 206 public int diskCacheSize = DEFAULT_DISK_CACHE_SIZE; 207 public CompressFormat compressFormat = DEFAULT_COMPRESS_FORMAT; 208 public int compressQuality = DEFAULT_COMPRESS_QUALITY; 209 public boolean memoryCacheEnabled = DEFAULT_MEM_CACHE_ENABLED; 210 public boolean diskCacheEnabled = DEFAULT_DISK_CACHE_ENABLED; 211 public boolean clearDiskCacheOnStart = DEFAULT_CLEAR_DISK_CACHE_ON_START; 212 ImageCacheParams(String uniqueName)213 public ImageCacheParams(String uniqueName) { 214 this.uniqueName = uniqueName; 215 } 216 } 217 } 218