Home | History | Annotate | Download | only in cache
      1 package com.bumptech.glide.load.engine.cache;
      2 
      3 import android.annotation.TargetApi;
      4 import android.app.ActivityManager;
      5 import android.content.Context;
      6 import android.os.Build;
      7 import android.util.DisplayMetrics;
      8 import android.util.Log;
      9 
     10 /**
     11  * A calculator that tries to intelligently determine cache sizes for a given device based on some constants and the
     12  * devices screen density, width, and height.
     13  */
     14 public class MemorySizeCalculator {
     15     private static final String TAG = "MemorySizeCalculator";
     16 
     17     static final int BYTES_PER_ARGB_8888_PIXEL = 4;
     18     static final int MEMORY_CACHE_TARGET_SCREENS = 2;
     19     static final int BITMAP_POOL_TARGET_SCREENS = 3;
     20 
     21     static final float MAX_SIZE_MULTIPLIER = 0.4f;
     22     static final float LOW_MEMORY_MAX_SIZE_MULTIPLIER = 0.33f;
     23     private final int bitmapPoolSize;
     24     private final int memoryCacheSize;
     25 
     26     interface ScreenDimensions {
     27         int getWidthPixels();
     28         int getHeightPixels();
     29     }
     30 
     31     public MemorySizeCalculator(Context context) {
     32         this((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE),
     33                 new DisplayMetricsScreenDimensions(context.getResources().getDisplayMetrics()));
     34     }
     35 
     36     MemorySizeCalculator(ActivityManager activityManager, ScreenDimensions screenDimensions) {
     37         final int maxSize = getMaxSize(activityManager);
     38 
     39         final int screenSize = screenDimensions.getWidthPixels() * screenDimensions.getHeightPixels()
     40                 * BYTES_PER_ARGB_8888_PIXEL;
     41 
     42         int targetPoolSize = screenSize * BITMAP_POOL_TARGET_SCREENS;
     43         int targetMemoryCacheSize = screenSize * MEMORY_CACHE_TARGET_SCREENS;
     44 
     45         if (targetMemoryCacheSize + targetPoolSize <= maxSize) {
     46             memoryCacheSize = targetMemoryCacheSize;
     47             bitmapPoolSize = targetPoolSize;
     48         } else {
     49             int part = Math.round((float) maxSize / (BITMAP_POOL_TARGET_SCREENS + MEMORY_CACHE_TARGET_SCREENS));
     50             memoryCacheSize = part * MEMORY_CACHE_TARGET_SCREENS;
     51             bitmapPoolSize = part * BITMAP_POOL_TARGET_SCREENS;
     52         }
     53 
     54         if (Log.isLoggable(TAG, Log.DEBUG)) {
     55             Log.d(TAG, "Calculated memory cache size: " + toMb(memoryCacheSize) + " pool size: " + toMb(bitmapPoolSize)
     56                     + " memory class limited? " + (targetMemoryCacheSize + targetPoolSize > maxSize) + " max size: "
     57                     + toMb(maxSize) + " memoryClass: " + activityManager.getMemoryClass() + " isLowMemoryDevice: "
     58                     + isLowMemoryDevice(activityManager));
     59         }
     60     }
     61 
     62     /**
     63      * Returns the recommended memory cache size for the device it is run on in bytes.
     64      */
     65     public int getMemoryCacheSize() {
     66         return memoryCacheSize;
     67     }
     68 
     69     /**
     70      * Returns the recommended bitmap pool size for the device it is run on in bytes.
     71      */
     72     public int getBitmapPoolSize() {
     73         return bitmapPoolSize;
     74     }
     75 
     76     private static int getMaxSize(ActivityManager activityManager) {
     77         final int memoryClassBytes = activityManager.getMemoryClass() * 1024 * 1024;
     78         final boolean isLowMemoryDevice = isLowMemoryDevice(activityManager);
     79         return Math.round(memoryClassBytes
     80                 * (isLowMemoryDevice ? LOW_MEMORY_MAX_SIZE_MULTIPLIER : MAX_SIZE_MULTIPLIER));
     81     }
     82 
     83     private static int toMb(int bytes) {
     84         return bytes / (1024 * 1024);
     85     }
     86 
     87     @TargetApi(Build.VERSION_CODES.KITKAT)
     88     private static boolean isLowMemoryDevice(ActivityManager activityManager) {
     89         final int sdkInt = Build.VERSION.SDK_INT;
     90         return sdkInt < Build.VERSION_CODES.HONEYCOMB
     91                 || (sdkInt >= Build.VERSION_CODES.KITKAT && activityManager.isLowRamDevice());
     92     }
     93 
     94     private static class DisplayMetricsScreenDimensions implements ScreenDimensions {
     95         private final DisplayMetrics displayMetrics;
     96 
     97         public DisplayMetricsScreenDimensions(DisplayMetrics displayMetrics) {
     98             this.displayMetrics = displayMetrics;
     99         }
    100 
    101         @Override
    102         public int getWidthPixels() {
    103             return displayMetrics.widthPixels;
    104         }
    105 
    106         @Override
    107         public int getHeightPixels() {
    108             return displayMetrics.heightPixels;
    109         }
    110     }
    111 }
    112