Высокое разрешение изображения - 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 Activity и заканчиваю его (), кажется, что есть ссылка на ImageView / изображение, хранящееся в памяти.

Как я могу уменьшить огромное потребление памяти?

Когда я не отображаю заставку, мое приложение потребляет только около 35 МБ памяти. С изображением SplashScreen его около 100 МБ.

2 ответа

Решение

Три подсказки, которые должны вам помочь:

  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;
    }
    
  2. Убедитесь, что у вас есть только один экземпляр вашего Bitmap в памяти. После отображения звоните recycle() и установите вашу ссылку на null, Вы можете использовать Memory Allocation Tracker, чтобы увидеть, что выделено. Вы также можете читать файлы HPROF, как это предлагается в комментариях.

  3. По умолчанию ARGB_8888 используется формат пикселей, что означает 4 байта на пиксель. Очень хорошая статья: качество растровых изображений, полосы и сглаживание. Ваше изображение в формате JPEG, поэтому оно не имеет прозрачности, поэтому вы тратите 1 байт на каждый пиксель для альфа-канала. Это не очень вероятно, но, возможно, с приемлемым качеством вы можете использовать еще более экономичный формат. Посмотри на них. Может быть RGB_565 например. Для пикселя требуется 2 байта, поэтому ваше изображение будет на 50% светлее. Вы можете включить дизеринг для улучшения качества RGB_565,

У меня была похожая проблема, и решение простое. Поместите изображение с высоким разрешением 1920x1080 px в каталог drawable-nodpi. Система не масштабирует ресурсы, помеченные этим квалификатором, независимо от плотности текущего экрана, что приводит к OutOfMemoryError, поэтому проблема должна исчезнуть.

Пожалуйста, ознакомьтесь с документацией по Android: http://developer.android.com/intl/es/guide/practices/screens_support.html

Надеюсь, поможет.

Другие вопросы по тегам