Изображение с высоким разрешением - OutOfMemoryError
Я разрабатываю приложение для Galaxy S4.
Одним из требований приложения является наличие SplashScreen, содержащего изображение 1920x1080. Его высокое качество .jpeg-изображение и размер изображения примерно 2 мегабайта.
Проблема в том, что я получаю OutOfMemoryError, как только я запускаю приложение. Я довольно ошеломлен, что это уже происходит с изображением размером всего в 2 мегабайта? Как я могу исправить эту проблему и отобразить изображение?
Изменение размеров или размера изображения не является параметром.
SplashScreen.java
public class Splashscreen extends Activity {
private static final int SPLASH_DURATION = 2000;
private boolean isBackPressed = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(LayoutParams.FLAG_FULLSCREEN, LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.splashscreen);
Handler h = new Handler();
h.postDelayed(new Runnable() {
@Override
public void run() {
// check if the backbutton has been pressed within the splash_duration
if(!isBackPressed) {
Intent i = new Intent(Splashscreen.this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Splashscreen.this.startActivity(i);
overridePendingTransition(R.anim.short_fade_in, R.anim.short_fade_out);
}
finish();
}
}, SPLASH_DURATION);
}
@Override
public void onBackPressed() {
isBackPressed = true;
super.onBackPressed();
}
}
И splashscreen.xml
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ivSplashScreenImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/high_res_splashscreen_image"/>
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ:
Иногда (когда доступно много памяти устройства) приложение может пройти мимо экрана всплеска, но затем потребление памяти приложения просто безумие. (около 100 мегабайт). Несмотря на то, что я закрываю активность SplashScreen и завершаю(), кажется, что есть ссылка на ImageView/Image, сохраненную в памяти.
Как уменьшить объем памяти в памяти?
Когда я не показываю заставку, мое приложение потребляет всего около 35 МБ памяти. С изображением SplashScreen - около 100 МБ.
Ответы
Ответ 1
Три подсказки, которые помогут вам:
-
Используйте это для загрузки изображений из Загрузка больших растровых изображений Документация для Android:
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
-
Убедитесь, что у вас есть только один экземпляр вашего Bitmap
в памяти. После его отображения вызовите recycle()
и установите ссылку null
. Вы можете использовать Tracker Allocation Tracker, чтобы узнать, что выделено. Вы также можете прочитать файлы HPROF, как это предлагается в комментариях.
-
По умолчанию используется формат пикселя ARGB_8888
, что означает 4 байта на пиксель. Очень хорошая статья: Растровое качество, группировка и сглаживание. Ваше изображение JPEG, поэтому у него нет прозрачности, поэтому вы тратите 1 байт на каждый пиксель для альфа-канала. Это не очень вероятно, но, возможно, с приемлемым качеством вы можете использовать еще более экономичный формат. Посмотрите на них. Может быть, например, RGB_565
. Он занимает 2 байта для пикселя, поэтому ваше изображение будет на 50% легче. Вы можете включить сглаживание для улучшения качества RGB_565
.
Ответ 2
У меня была аналогичная проблема, и решение прост. Поместите изображение с высоким разрешением 1920x1080 пикселей в каталог drawable-nodpi. Система не масштабирует ресурсы, помеченные этим квалификатором, независимо от текущей плотности экрана, что приводит к OutOfMemoryError, поэтому проблема должна исчезнуть.
Пожалуйста, проверьте документацию на Android: http://developer.android.com/intl/es/guide/practices/screens_support.html
Надеюсь, что это поможет.