Подтвердить что ты не робот

Android Bitmap загружает ошибку памяти Galaxy S3 WXGA

Я был бы очень признателен, если бы кто-то мог подтвердить, что я правильно решил проблему ниже или если есть альтернативное решение?

У меня есть приложение, которое загружает большое изображение (например, 800 * 1720 пикселей) в память и отображает его в scrollview. Изображение представляет собой план этажей для музея, и мне нужна простая карта, например, опыт прокрутки и масштабирования. Изображение загрузилось отлично на более старые устройства, но вызвало ошибку из памяти на Samsung Galaxy S3.

Глядя на сообщения LogCat, выяснилось, что при создании растрового изображения 22MB выделялось для растрового изображения вместо 800 * 1720 * 4 = 5,5 МБ. По существу, в 4 раза больше памяти выделялось по требованию других устройств и нажимало использование памяти на размер кучи размером 50 МБ.

Рекомендуемое решение этой проблемы - использовать параметр BitmapFactory.Options.inSampleSize, чтобы уменьшить разрешение загруженного изображения и потребовать меньше памяти. Однако это снижает качество изображения, и я действительно хочу отображать его на полном размере в оригинальном качестве, так как отлично работает на старых устройствах.

После большой царапины головы я пришел к выводу, что проблема заключается в том, что плотность пикселей на экранах S3 WXGA составляет 2,0 и, следовательно, для каждого пикселя на изображении, битмап фактически выделяет 4 пикселя. С небольшим количеством проб и ошибок я обнаружил, что могу предотвратить это, установив options.inScaled = false;

http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inScaled

По пути я также понял, что могу сократить использование памяти в два раза до 2,7 МБ, используя более низкую глубину цвета 2 пикселя вместо 4 пикселей, установив options.inPreferredConfig = Bitmap.Config.RGB_565;. Для моих напольных покрытий это не повлияло на качество видимого изображения.

Окончательный код был таким образом:

String uri = "drawable/floorplan";
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inScaled = false;
Bitmap bm = BitmapFactory.decodeResource(getResources(), imageResource, options);
IVfloorplan.setImageBitmap(bm);

При отображении этого растрового изображения вам нужно масштабировать его. Чтобы выработать масштаб, вы можете получить плотность пикселей из:

float density = getResources().getDisplayMetrics().density;

Я уменьшил использование памяти для растрового изображения с 22 МБ до 2,7 МБ, что в куче 50 МБ значительно.

4b9b3361

Ответ 1

Экран S3 имеет действительно высокое разрешение, поэтому он вполне понятен. Кроме того, если изображение находится в выпадающей папке, оно может автоматически масштабироваться. Могут быть способы отключить это. Даже если ваш размер изображения не является случайным, ОС должна выделять буфер для размещения изображения, а также, возможно, один для размещения его на экране.

Альтернативой является использование тайлинга, который используется в играх, таких как игры SNES. Это также то, как они обрабатывали множество графических элементов без исчерпания ОЗУ. Доказательства показывают, что именно так Google Maps имеет карту планеты Земля. Вы в основном разбиваете большое изображение на плитки и показываете плитку на экране, когда вы подходите к ним (конечно, возможно, по 1 дополнительной плитки с каждой стороны).

Несмотря на то, что это post-Honeycomb, где Google вводит код для лучшего управления распределением Bitmap, будьте осторожны с распределением Bitmap. Это больше похоже на программу на C, чем на Java-программу, и это хорошая идея, чтобы управлять им, как один. Очень просто выбежать из кучи пространства при использовании объектов Bitmap в Android