1package com.bumptech.glide; 2 3import android.annotation.TargetApi; 4import android.app.Activity; 5import android.content.ComponentCallbacks2; 6import android.content.Context; 7import android.graphics.Bitmap; 8import android.graphics.drawable.BitmapDrawable; 9import android.graphics.drawable.Drawable; 10import android.net.Uri; 11import android.os.ParcelFileDescriptor; 12import android.support.v4.app.Fragment; 13import android.support.v4.app.FragmentActivity; 14import android.util.Log; 15import android.view.View; 16import android.widget.ImageView; 17import com.android.volley.RequestQueue; 18import com.bumptech.glide.load.engine.Engine; 19import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 20import com.bumptech.glide.load.engine.cache.DiskCache; 21import com.bumptech.glide.load.engine.cache.MemoryCache; 22import com.bumptech.glide.load.model.GenericLoaderFactory; 23import com.bumptech.glide.load.model.GlideUrl; 24import com.bumptech.glide.load.model.ImageVideoWrapper; 25import com.bumptech.glide.load.model.ModelLoader; 26import com.bumptech.glide.load.model.ModelLoaderFactory; 27import com.bumptech.glide.load.model.file_descriptor.FileDescriptorFileLoader; 28import com.bumptech.glide.load.model.file_descriptor.FileDescriptorModelLoader; 29import com.bumptech.glide.load.model.file_descriptor.FileDescriptorResourceLoader; 30import com.bumptech.glide.load.model.file_descriptor.FileDescriptorStringLoader; 31import com.bumptech.glide.load.model.file_descriptor.FileDescriptorUriLoader; 32import com.bumptech.glide.load.model.stream.StreamFileLoader; 33import com.bumptech.glide.load.model.stream.StreamModelLoader; 34import com.bumptech.glide.load.model.stream.StreamResourceLoader; 35import com.bumptech.glide.load.model.stream.StreamStringLoader; 36import com.bumptech.glide.load.model.stream.StreamUriLoader; 37import com.bumptech.glide.load.model.stream.StreamUrlLoader; 38import com.bumptech.glide.load.resource.bitmap.CenterCrop; 39import com.bumptech.glide.load.resource.bitmap.FileDescriptorBitmapDataLoadProvider; 40import com.bumptech.glide.load.resource.bitmap.FitCenter; 41import com.bumptech.glide.load.resource.bitmap.ImageVideoDataLoadProvider; 42import com.bumptech.glide.load.resource.bitmap.StreamBitmapDataLoadProvider; 43import com.bumptech.glide.load.resource.gif.GifData; 44import com.bumptech.glide.load.resource.gif.GifDataLoadProvider; 45import com.bumptech.glide.load.resource.gif.GifDrawable; 46import com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapper; 47import com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapperTransformation; 48import com.bumptech.glide.load.resource.gifbitmap.ImageVideoGifDataLoadProvider; 49import com.bumptech.glide.load.resource.transcode.BitmapDrawableTranscoder; 50import com.bumptech.glide.load.resource.transcode.GifBitmapWrapperDrawableTranscoder; 51import com.bumptech.glide.load.resource.transcode.GifDataDrawableTranscoder; 52import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; 53import com.bumptech.glide.load.resource.transcode.TranscoderFactory; 54import com.bumptech.glide.manager.RequestManagerRetriever; 55import com.bumptech.glide.provider.DataLoadProviderFactory; 56import com.bumptech.glide.request.GlideAnimation; 57import com.bumptech.glide.request.Request; 58import com.bumptech.glide.request.target.ImageViewTargetFactory; 59import com.bumptech.glide.request.target.Target; 60import com.bumptech.glide.request.target.ViewTarget; 61import com.bumptech.glide.volley.VolleyUrlLoader; 62 63import java.io.File; 64import java.io.InputStream; 65import java.net.URL; 66 67/** 68 * A singleton to present a simple static interface for building requests with {@link BitmapRequestBuilder} and maintaining 69 * an {@link Engine}, {@link BitmapPool}, {@link DiskCache} and {@link MemoryCache}. 70 * 71 * <p> 72 * Note - This class is not thread safe. 73 * </p> 74 */ 75public class Glide { 76 // 250 MB 77 static final int DEFAULT_DISK_CACHE_SIZE = 250 * 1024 * 1024; 78 79 private static final String DEFAULT_DISK_CACHE_DIR = "image_manager_disk_cache"; 80 private static final String TAG = "Glide"; 81 private static Glide GLIDE; 82 83 private final GenericLoaderFactory loaderFactory = new GenericLoaderFactory(); 84 private final RequestQueue requestQueue; 85 private final Engine engine; 86 private final BitmapPool bitmapPool; 87 private final MemoryCache memoryCache; 88 private final ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory(); 89 private final TranscoderFactory transcoderFactory = new TranscoderFactory(); 90 private final DataLoadProviderFactory dataLoadProviderFactory; 91 private final CenterCrop bitmapCenterCrop; 92 private final GifBitmapWrapperTransformation drawableCenterCrop; 93 private final FitCenter bitmapFitCenter; 94 private final GifBitmapWrapperTransformation drawableFitCenter; 95 96 /** 97 * Try to get the external cache directory if available and default to the internal. Use a default name for the 98 * cache directory if no name is provided 99 * 100 * @param context A context 101 * @return A File representing the default disk cache directory 102 */ 103 public static File getPhotoCacheDir(Context context) { 104 return getPhotoCacheDir(context, DEFAULT_DISK_CACHE_DIR); 105 } 106 107 /** 108 * Try to get the external cache directory if available and default to the internal. Use a default name for the 109 * cache directory if no name is provided 110 * 111 * @param context A context 112 * @param cacheName The name of the subdirectory in which to store the cache 113 * @return A File representing the default disk cache directory 114 */ 115 @SuppressWarnings("ResultOfMethodCallIgnored") 116 public static File getPhotoCacheDir(Context context, String cacheName) { 117 File cacheDir = context.getCacheDir(); 118 if (cacheDir != null) { 119 File result = new File(cacheDir, cacheName); 120 result.mkdirs(); 121 return result; 122 } 123 if (Log.isLoggable(TAG, Log.ERROR)) { 124 Log.e(TAG, "default disk cache dir is null"); 125 } 126 return null; 127 } 128 129 /** 130 * Get the singleton. 131 * 132 * @return the singleton 133 */ 134 public static Glide get(Context context) { 135 if (GLIDE == null) { 136 GLIDE = new GlideBuilder(context).createGlide(); 137 } 138 139 return GLIDE; 140 } 141 142 /** 143 * Returns false if the {@link Glide} singleton has not yet been created and can therefore be setup using 144 * {@link #setup(GlideBuilder)}. 145 * 146 * @see #setup(GlideBuilder) 147 */ 148 public static boolean isSetup() { 149 return GLIDE != null; 150 } 151 152 /** 153 * Creates the {@link Glide} singleton using the given builder. Can be used to set options like cache sizes and 154 * locations. 155 * 156 * @see #isSetup() 157 * 158 * @param builder The builder. 159 * @throws IllegalArgumentException if the Glide singleton has already been created. 160 */ 161 public static void setup(GlideBuilder builder) { 162 if (isSetup()) { 163 throw new IllegalArgumentException("Glide is already setup, check with isSetup() first"); 164 } 165 166 GLIDE = builder.createGlide(); 167 } 168 169 static void tearDown() { 170 GLIDE = null; 171 } 172 173 Glide(Engine engine, RequestQueue requestQueue, MemoryCache memoryCache, BitmapPool bitmapPool, 174 Context context) { 175 this.engine = engine; 176 this.requestQueue = requestQueue; 177 this.bitmapPool = bitmapPool; 178 this.memoryCache = memoryCache; 179 180 dataLoadProviderFactory = new DataLoadProviderFactory(); 181 182 dataLoadProviderFactory.register(InputStream.class, Bitmap.class, new StreamBitmapDataLoadProvider(bitmapPool)); 183 dataLoadProviderFactory.register(ParcelFileDescriptor.class, Bitmap.class, 184 new FileDescriptorBitmapDataLoadProvider(bitmapPool)); 185 186 ImageVideoDataLoadProvider imageVideoDataLoadProvider = new ImageVideoDataLoadProvider(bitmapPool); 187 dataLoadProviderFactory.register(ImageVideoWrapper.class, Bitmap.class, imageVideoDataLoadProvider); 188 189 GifDataLoadProvider gifDataLoadProvider = new GifDataLoadProvider(context, bitmapPool); 190 dataLoadProviderFactory.register(InputStream.class, GifData.class, gifDataLoadProvider); 191 192 dataLoadProviderFactory.register(ImageVideoWrapper.class, GifBitmapWrapper.class, 193 new ImageVideoGifDataLoadProvider(imageVideoDataLoadProvider, gifDataLoadProvider)); 194 195 register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory()); 196 register(File.class, InputStream.class, new StreamFileLoader.Factory()); 197 register(Integer.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory()); 198 register(Integer.class, InputStream.class, new StreamResourceLoader.Factory()); 199 register(String.class, ParcelFileDescriptor.class, new FileDescriptorStringLoader.Factory()); 200 register(String.class, InputStream.class, new StreamStringLoader.Factory()); 201 register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory()); 202 register(Uri.class, InputStream.class, new StreamUriLoader.Factory()); 203 register(URL.class, InputStream.class, new StreamUrlLoader.Factory()); 204 register(GlideUrl.class, InputStream.class, new VolleyUrlLoader.Factory(requestQueue)); 205 206 transcoderFactory.register(Bitmap.class, BitmapDrawable.class, 207 new BitmapDrawableTranscoder(context.getResources(), bitmapPool)); 208 transcoderFactory.register(GifBitmapWrapper.class, Drawable.class, 209 new GifBitmapWrapperDrawableTranscoder(new BitmapDrawableTranscoder(context.getResources(), bitmapPool), 210 new GifDataDrawableTranscoder())); 211 transcoderFactory.register(GifData.class, GifDrawable.class, new GifDataDrawableTranscoder()); 212 213 bitmapCenterCrop = new CenterCrop(bitmapPool); 214 drawableCenterCrop = new GifBitmapWrapperTransformation(bitmapCenterCrop); 215 216 bitmapFitCenter = new FitCenter(bitmapPool); 217 drawableFitCenter = new GifBitmapWrapperTransformation(bitmapFitCenter); 218 } 219 220 public BitmapPool getBitmapPool() { 221 return bitmapPool; 222 } 223 224 <Z, R> ResourceTranscoder<Z, R> buildTranscoder(Class<Z> decodedClass, Class<R> transcodedClass) { 225 return transcoderFactory.get(decodedClass, transcodedClass); 226 } 227 228 <T, Z> DataLoadProvider<T, Z> buildDataProvider(Class<T> dataClass, Class<Z> decodedClass) { 229 return dataLoadProviderFactory.get(dataClass, decodedClass); 230 } 231 232 <R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) { 233 return imageViewTargetFactory.buildTarget(imageView, transcodedClass); 234 } 235 236 Engine getEngine() { 237 return engine; 238 } 239 240 CenterCrop getBitmapCenterCrop() { 241 return bitmapCenterCrop; 242 } 243 244 FitCenter getBitmapFitCenter() { 245 return bitmapFitCenter; 246 } 247 248 GifBitmapWrapperTransformation getDrawableCenterCrop() { 249 return drawableCenterCrop; 250 } 251 252 GifBitmapWrapperTransformation getDrawableFitCenter() { 253 return drawableFitCenter; 254 } 255 256 private GenericLoaderFactory getLoaderFactory() { 257 return loaderFactory; 258 } 259 260 /** 261 * Returns the {@link RequestQueue} Glide is using to fetch images over http/https. 262 */ 263 public RequestQueue getRequestQueue() { 264 return requestQueue; 265 } 266 267 /** 268 * Clears as much memory as possible. 269 * 270 * @see ComponentCallbacks2#onLowMemory() 271 */ 272 public void clearMemory() { 273 bitmapPool.clearMemory(); 274 memoryCache.clearMemory(); 275 } 276 277 /** 278 * Clears some memory with the exact amount depending on the given level. 279 * 280 * @see ComponentCallbacks2#onTrimMemory(int) 281 */ 282 public void trimMemory(int level) { 283 bitmapPool.trimMemory(level); 284 memoryCache.trimMemory(level); 285 } 286 287 /** 288 * Adjusts Glide's current and maximum memory usage based on the given {@link MemoryCategory}. 289 * 290 * <p> 291 * The default {@link MemoryCategory} is {@link MemoryCategory#NORMAL}. {@link MemoryCategory#HIGH} increases 292 * Glide's maximum memory usage by up to 50% and {@link MemoryCategory#LOW} decreases Glide's maximum memory 293 * usage by 50%. This method should be used to temporarily increase or decrease memory useage for a single 294 * Activity or part of the app. Use {@link GlideBuilder#setMemoryCache(MemoryCache)} to set a permanent 295 * memory size if you want to change the default. 296 * </p> 297 */ 298 public void setMemoryCategory(MemoryCategory memoryCategory) { 299 memoryCache.setSizeMultiplier(memoryCategory.getMultiplier()); 300 bitmapPool.setSizeMultiplier(memoryCategory.getMultiplier()); 301 } 302 303 /** 304 * Cancel any pending loads Glide may have for the target and free any resources (such as {@link Bitmap}s) that may 305 * have been loaded for the target so they may be reused. 306 * 307 * @param target The Target to cancel loads for. 308 */ 309 public static void clear(Target target) { 310 Request request = target.getRequest(); 311 if (request!= null) { 312 request.clear(); 313 } 314 } 315 316 /** 317 * Cancel any pending loads Glide may have for the view and free any resources that may have been loaded for the 318 * view. 319 * 320 * <p> 321 * Note that this will only work if {@link View#setTag(Object)} is not called on this view outside of Glide. 322 * </p> 323 * 324 * @see #clear(Target). 325 * 326 * @param view The view to cancel loads and free resources for. 327 * @throws IllegalArgumentException if an object other than Glide's metadata is set as the view's tag. 328 */ 329 public static void clear(View view) { 330 Target viewTarget = new ClearTarget(view); 331 clear(viewTarget); 332 } 333 334 /** 335 * Use the given factory to build a {@link ModelLoader} for models of the given class. Generally the best use of 336 * this method is to replace one of the default factories or add an implementation for other similar low level 337 * models. Typically the {@link RequestManager#using(StreamModelLoader)} or 338 * {@link RequestManager#using(FileDescriptorModelLoader)} syntax is preferred because it directly links the model 339 * with the ModelLoader being used to load it. Any factory replaced by the given factory will have its 340 * {@link ModelLoaderFactory#teardown()}} method called. 341 * 342 * <p> 343 * Note - If a factory already exists for the given class, it will be replaced. If that factory is not being 344 * used for any other model class, {@link ModelLoaderFactory#teardown()} 345 * will be called. 346 * </p> 347 * 348 * <p> 349 * Note - The factory must not be an anonymous inner class of an Activity or another object that cannot be 350 * retained statically. 351 * </p> 352 * 353 * @see RequestManager#using(FileDescriptorModelLoader) 354 * @see RequestManager#using(StreamModelLoader) 355 * 356 * @param modelClass The model class. 357 * @param resourceClass The resource class the model loader will translate the model type into. 358 * @param factory The factory to use. 359 * @param <T> The type of the model. 360 * @param <Y> the type of the resource. 361 */ 362 public <T, Y> void register(Class<T> modelClass, Class<Y> resourceClass, ModelLoaderFactory<T, Y> factory) { 363 ModelLoaderFactory<T, Y> removed = loaderFactory.register(modelClass, resourceClass, factory); 364 if (removed != null) { 365 removed.teardown(); 366 } 367 } 368 369 /** 370 * Removes any {@link ModelLoaderFactory} registered for the given model and resource classes if one exists. If a 371 * {@link ModelLoaderFactory} is removed, its {@link ModelLoaderFactory#teardown()}} method will be called. 372 * 373 * @param modelClass The model class. 374 * @param resourceClass The resource class. 375 * @param <T> The type of the model. 376 * @param <Y> The type of the resource. 377 */ 378 public <T, Y> void unregister(Class<T> modelClass, Class<Y> resourceClass) { 379 ModelLoaderFactory<T, Y> removed = loaderFactory.unregister(modelClass, resourceClass); 380 if (removed != null) { 381 removed.teardown(); 382 } 383 } 384 385 /** 386 * Build a {@link ModelLoader} for the given model class using registered {@link ModelLoaderFactory}s. 387 * 388 * @see #buildModelLoader(Object, Class, Context) 389 * @see #buildStreamModelLoader(Class, Context) 390 * @see #buildFileDescriptorModelLoader(Class, Context) 391 * 392 * @param modelClass The class to get a {@link ModelLoader} for. 393 * @param resourceClass The resource class to get a {@link ModelLoader} for. 394 * @param context Any context. 395 * @param <T> The type of the model. 396 * @param <Y> The type of the resource. 397 * @return A new {@link ModelLoader} for the given model class. 398 */ 399 public static <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass, 400 Context context) { 401 return Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass, context); 402 } 403 404 /** 405 * A convenience method to build a {@link ModelLoader} for a given model object using registered 406 * {@link ModelLoaderFactory}s. 407 * 408 * @see #buildModelLoader(Class, Class, Context) 409 * 410 * @param model A non null model object whose class we will get a {@link ModelLoader} for. 411 * @param resourceClass The resource class to get a {@link ModelLoader} for. 412 * @param context Any context. 413 * @param <T> The type of the model. 414 * @param <Y> The type of the resource. 415 * @return A new {@link ModelLoader} for the given model and resource classes, or null if model is null. 416 */ 417 @SuppressWarnings("unchecked") 418 public static <T, Y> ModelLoader<T, Y> buildModelLoader(T model, Class<Y> resourceClass, Context context) { 419 if (model == null) { 420 if (Log.isLoggable(TAG, Log.DEBUG)) { 421 Log.d(TAG, "Unable to load null model, setting placeholder only"); 422 } 423 return null; 424 } 425 return buildModelLoader((Class<T>) model.getClass(), resourceClass, context); 426 } 427 428 /** 429 * A method to build a {@link ModelLoader} for the given model that produces {@link InputStream}s using a registered 430 * factory. 431 * 432 * @see #buildModelLoader(Class, Class, android.content.Context) 433 */ 434 public static <T> ModelLoader<T, InputStream> buildStreamModelLoader(Class<T> modelClass, Context context) { 435 return buildModelLoader(modelClass, InputStream.class, context); 436 } 437 438 /** 439 * A method to build a {@link ModelLoader} for the given model that produces {@link InputStream}s using a registered 440 * factory. 441 * 442 * @see #buildModelLoader(Object, Class, Context) 443 */ 444 public static <T> ModelLoader<T, InputStream> buildStreamModelLoader(T model, Context context) { 445 return buildModelLoader(model, InputStream.class, context); 446 } 447 448 /** 449 * A method to build a {@link ModelLoader} for the given model class that produces 450 * {@link ParcelFileDescriptor}s using a registered factory. 451 * 452 * @see #buildModelLoader(Class, Class, android.content.Context) 453 */ 454 public static <T> ModelLoader<T, ParcelFileDescriptor> buildFileDescriptorModelLoader(Class<T> modelClass, 455 Context context) { 456 return buildModelLoader(modelClass, ParcelFileDescriptor.class, context); 457 } 458 459 /** 460 * A method to build a {@link ModelLoader} for the given model class that produces 461 * {@link ParcelFileDescriptor}s using a registered factory. 462 * 463 * @see #buildModelLoader(Object, Class, android.content.Context) 464 */ 465 public static <T> ModelLoader<T, ParcelFileDescriptor> buildFileDescriptorModelLoader(T model, Context context) { 466 return buildModelLoader(model, ParcelFileDescriptor.class, context); 467 } 468 469 /** 470 * Begin a load with Glide by passing in a context. 471 * 472 * @param context Any context, will not be retained. 473 * @return A model request to pass in the object representing the image to be loaded. 474 */ 475 public static RequestManager with(Context context) { 476 return RequestManagerRetriever.get(context); 477 } 478 479 public static RequestManager with(Activity activity) { 480 return RequestManagerRetriever.get(activity); 481 } 482 483 public static RequestManager with(FragmentActivity activity) { 484 return RequestManagerRetriever.get(activity); 485 } 486 487 @TargetApi(11) 488 public static RequestManager with(android.app.Fragment fragment) { 489 return RequestManagerRetriever.get(fragment); 490 } 491 492 public static RequestManager with(Fragment fragment) { 493 return RequestManagerRetriever.get(fragment); 494 } 495 496 private static class ClearTarget extends ViewTarget<View, Object> { 497 public ClearTarget(View view) { 498 super(view); 499 } 500 501 @Override 502 public void onResourceReady(Object resource, GlideAnimation<Object> glideAnimation) { } 503 504 @Override 505 public void setPlaceholder(Drawable placeholder) { } 506 } 507} 508