Это конец 2018 года, так что все изменилось.
Прежде всего: запустите приложение и откройте вкладку Android Profiler в Android Studio. Вы увидите, сколько памяти он потребляет, вы будете удивлены, но он может выделить много оперативной памяти.
Также здесь есть отличная статья в официальных документах с подробными инструкциями о том, как использовать Memory Profiler, которая может дать вам всесторонний обзор управления вашей памятью.
Но в большинстве случаев вам будет достаточно обычного Android Profiler.
Обычно приложение запускается с 50 МБ памяти, но при загрузке некоторых фотографий в память мгновенно увеличивается до 90 МБ. Когда вы открываете Activity с помощью ViewPager с предварительно загруженными фотографиями (по 3,5 МБ каждая), вы можете легко получить 190 МБ за несколько секунд.
Но это не значит, что у вас есть проблемы с управлением памятью.
Лучший совет, который я могу дать, - следовать рекомендациям и рекомендациям, использовать лучшие библиотеки для загрузки изображений (Glide, Picasso), и все будет в порядке.
Но если вам нужно что-то адаптировать, и вам действительно нужно знать, сколько памяти вы можете выделить вручную, вы можете получить полную свободную память и рассчитать заранее определенную часть (в%) из нее. В моем случае мне нужно было кэшировать расшифрованные фотографии в памяти, поэтому мне не нужно расшифровывать их каждый раз, когда пользователь просматривает список.
Для этого вы можете использовать готовый к использованию класс LruCache . Это класс кеша, который автоматически отслеживает, сколько памяти выделяют ваши объекты (или количество экземпляров), и удаляет самые старые, чтобы сохранить последние по истории их использования.
Вот отличный урок о том, как его использовать.
В моем случае я создал 2 экземпляра кешей: для больших пальцев и вложений. Сделайте их статичными с одноэлементным доступом, чтобы они были доступны во всем приложении.
класс кеша:
public class BitmapLruCache extends LruCache<Uri, byte[]> {
private static final float CACHE_PART_FOR_THUMBS_PRC = 0.01f; // 1% (Nexus 5X - 5Mb)
private static final float CACHE_PART_FOR_ATTACHMENTS_PRC = 0.03f;// 3% (Nexus 5X - 16Mb)
private static BitmapLruCache thumbCacheInstance;
private static BitmapLruCache attachmentCacheInstance;
public static synchronized BitmapLruCache getDecryptedThumbCacheInstance() {
if (thumbCacheInstance == null) {
int cacheSize = getCacheSize(CACHE_PART_FOR_THUMBS_PRC);
//L.log("creating BitmapLruCache for Thumb with size: " + cacheSize + " bytes");
thumbCacheInstance = new BitmapLruCache(cacheSize);
return thumbCacheInstance;
} else {
return thumbCacheInstance;
}
}
public static synchronized BitmapLruCache getDecryptedAttachmentCacheInstance() {
if (attachmentCacheInstance == null) {
int cacheSize = getCacheSize(CACHE_PART_FOR_ATTACHMENTS_PRC);
// L.log("creating BitmapLruCache for Attachment with size: " + cacheSize + " bytes");
attachmentCacheInstance = new BitmapLruCache(cacheSize);
return attachmentCacheInstance;
} else {
return attachmentCacheInstance;
}
}
private BitmapLruCache(int maxSize) {
super(maxSize);
}
public void addBitmap(Uri uri, byte[] bitmapBytes) {
if (get(uri) == null && bitmapBytes != null)
put(uri, bitmapBytes);
}
public byte[] getBitmap(Uri uri) {
return get(uri);
}
@Override
protected int sizeOf(Uri uri, byte[] bitmapBytes) {
// The cache size will be measured in bytes rather than number of items.
return bitmapBytes.length;
}
}
Вот как я вычисляю доступную свободную оперативную память и сколько я могу укусить из нее:
private static int getCacheSize(float partOfTotalFreeMemoryToUseAsCache){
final long maxMemory = Runtime.getRuntime().maxMemory();
//Use ... of available memory for List Notes thumb cache
return (int) (maxMemory * partOfTotalFreeMemoryToUseAsCache);
}
И вот как я использую его в адаптерах для получения кэшированного изображения:
byte[] decryptedThumbnail = BitmapLruCache.getDecryptedThumbCacheInstance().getBitmap(thumbUri);
и как я устанавливаю его в кэш в фоновом потоке (обычный AsyncTask):
BitmapLruCache.getDecryptedThumbCacheInstance().addBitmap(thumbUri, thumbBytes);
Мое приложение предназначено для API 19+, поэтому устройства не устарели, и в моем случае эти части доступной оперативной памяти достаточно хороши для кэширования (1% и 3%).
Интересный факт: Android не имеет API или других хаков, чтобы получить объем памяти, выделенный для вашего приложения, он рассчитывается на лету на основе различных факторов.
PS Я использую поле статического класса для хранения кэша, но в соответствии с последними рекомендациями Android рекомендуется использовать для этой цели компонент архитектуры ViewModel .