blob: d3f9d758cba7082ac792dbcf3064dd9f9c3c7b1c [file] [log] [blame]
package com.bumptech.glide.load.engine.cache;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.Context;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.Log;
/**
* A calculator that tries to intelligently determine cache sizes for a given device based on some constants and the
* devices screen density, width, and height.
*/
public class MemorySizeCalculator {
private static final String TAG = "MemorySizeCalculator";
static final int BYTES_PER_ARGB_8888_PIXEL = 4;
static final int MEMORY_CACHE_TARGET_SCREENS = 2;
static final int BITMAP_POOL_TARGET_SCREENS = 3;
static final float MAX_SIZE_MULTIPLIER = 0.4f;
static final float LOW_MEMORY_MAX_SIZE_MULTIPLIER = 0.33f;
private final int bitmapPoolSize;
private final int memoryCacheSize;
interface ScreenDimensions {
int getWidthPixels();
int getHeightPixels();
}
public MemorySizeCalculator(Context context) {
this((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE),
new DisplayMetricsScreenDimensions(context.getResources().getDisplayMetrics()));
}
MemorySizeCalculator(ActivityManager activityManager, ScreenDimensions screenDimensions) {
final int maxSize = getMaxSize(activityManager);
final int screenSize = screenDimensions.getWidthPixels() * screenDimensions.getHeightPixels()
* BYTES_PER_ARGB_8888_PIXEL;
int targetPoolSize = screenSize * BITMAP_POOL_TARGET_SCREENS;
int targetMemoryCacheSize = screenSize * MEMORY_CACHE_TARGET_SCREENS;
if (targetMemoryCacheSize + targetPoolSize <= maxSize) {
memoryCacheSize = targetMemoryCacheSize;
bitmapPoolSize = targetPoolSize;
} else {
int part = Math.round((float) maxSize / (BITMAP_POOL_TARGET_SCREENS + MEMORY_CACHE_TARGET_SCREENS));
memoryCacheSize = part * MEMORY_CACHE_TARGET_SCREENS;
bitmapPoolSize = part * BITMAP_POOL_TARGET_SCREENS;
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Calculated memory cache size: " + toMb(memoryCacheSize) + " pool size: " + toMb(bitmapPoolSize)
+ " memory class limited? " + (targetMemoryCacheSize + targetPoolSize > maxSize) + " max size: "
+ toMb(maxSize) + " memoryClass: " + activityManager.getMemoryClass() + " isLowMemoryDevice: "
+ isLowMemoryDevice(activityManager));
}
}
/**
* Returns the recommended memory cache size for the device it is run on in bytes.
*/
public int getMemoryCacheSize() {
return memoryCacheSize;
}
/**
* Returns the recommended bitmap pool size for the device it is run on in bytes.
*/
public int getBitmapPoolSize() {
return bitmapPoolSize;
}
private static int getMaxSize(ActivityManager activityManager) {
final int memoryClassBytes = activityManager.getMemoryClass() * 1024 * 1024;
final boolean isLowMemoryDevice = isLowMemoryDevice(activityManager);
return Math.round(memoryClassBytes
* (isLowMemoryDevice ? LOW_MEMORY_MAX_SIZE_MULTIPLIER : MAX_SIZE_MULTIPLIER));
}
private static int toMb(int bytes) {
return bytes / (1024 * 1024);
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private static boolean isLowMemoryDevice(ActivityManager activityManager) {
final int sdkInt = Build.VERSION.SDK_INT;
return sdkInt < Build.VERSION_CODES.HONEYCOMB
|| (sdkInt >= Build.VERSION_CODES.KITKAT && activityManager.isLowRamDevice());
}
private static class DisplayMetricsScreenDimensions implements ScreenDimensions {
private final DisplayMetrics displayMetrics;
public DisplayMetricsScreenDimensions(DisplayMetrics displayMetrics) {
this.displayMetrics = displayMetrics;
}
@Override
public int getWidthPixels() {
return displayMetrics.widthPixels;
}
@Override
public int getHeightPixels() {
return displayMetrics.heightPixels;
}
}
}