Исключение нехватки памяти с растровыми изображениями

у меня проблема в моем приложении. При переключении в режим наземного пространства вызывается метод setContentView() для отображения клавиатуры пианино. Класс клавиатуры пианино расширяет Surfaceview для лучшего отображения нажатых клавиш. Этот класс SurfaceView добавляется как дочерний в мой альбомный макет:

RelativeLayout rootLayout = (RelativeLayout) findViewById(R.id.rootLayout);
RelativeLayout.LayoutParams relativeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
relativeLayoutParams.addRule(RelativeLayout.BELOW, R.id.relativeLayoutLowerBar);
rootLayout.addView(keyboardSurfaceView, relativeLayoutParams); 

В моем классе keyboardSurfaceView я загружаю растровые изображения в массив растровых изображений с помощью метода BitmapFactory.decodeResource() и удерживаю растровые изображения до тех пор, пока приложение не будет уничтожено. Это прекрасно работает. Когда я переключаюсь в портретный режим, я меняю макет с помощью setContentView() и удаляю keyboardSurfaceView :

if(keyboardSurfaceView != null && keyboardSurfaceView.getParent() != null)
        ((ViewGroup) keyboardSurfaceView.getParent()).removeView(keyboardSurfaceView);

Растровые изображения загружаются один раз. Первый раз при переключении в ландшафтный режим. Я столкнулся с ошибкой нехватки памяти, когда переключался до 10-20 раз с портрета на пейзаж и так далее. Когда я обновляю кучу в представлении ddms, я вижу, что каждый раз, когда я переключаюсь с вертикального вида на альбомный, размер кучи увеличивается до ок. 20 мб, а затем приложение вылетает. Я не знаю, почему это происходит все время. Растровые изображения загружаются только один раз, а не каждый раз. Я также пробовал bitmap.recycle(); bitmap = nullбезуспешно. Также пытался кэшировать растровые изображения с помощью класса LRUCache, как описано в рекомендациях Google. Я также искал в stackoverflow подходящее решение для моей проблемы. До сих пор это не исправить. Я сам обрабатываю портретные/ландшафтные изменения (метод onConfigurationChanged() переопределен). Помещение всех изображений в drawable-xhdpi немного помогло. Размер кучи растет, как и раньше, при смене ориентации, но все равно растет. Любая помощь будет оценена...

Исключение:

 02-13 22:44:09.419: E/dalvikvm-heap(935): 11448-byte external allocation too large for this process.
02-13 22:44:09.419: E/dalvikvm(935): Out of memory: Heap Size=16391KB, Allocated=13895KB, Bitmap Size=16394KB, Limit=32768KB
02-13 22:44:09.419: E/dalvikvm(935): Trim info: Footprint=16391KB, Allowed Footprint=16391KB, Trimmed=432KB
02-13 22:44:09.419: E/GraphicsJNI(935): VM won't let us allocate 11448 bytes

person pawlinsky    schedule 13.02.2013    source источник


Ответы (2)


Вот документ Android о том, как эффективно обрабатывать растровые изображения

http://developer.android.com/training/displaying-bitmaps/index.html

person Pongpat    schedule 13.02.2013
comment
я это уже читал, но безуспешно. Проблема в растущей куче, хотя растровые изображения уже находятся в памяти. - person pawlinsky; 14.02.2013
comment
Если да, можете ли вы опубликовать больше кода, так как ваш код может содержать ошибку где-то еще. - person Pongpat; 14.02.2013

Хорошо, первый раз, когда в моем классе SurfaceView вызывается surfaceCreated, я вызываю этот метод, и этот метод вызывается только один раз, а не каждый раз, когда я показываю SurfaceView на экране:

bitmapKeyboard = BitmapFactory.decodeResource(context.getResources(), R.drawable.keyboard); 

bitmapGlowImages[0] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keycdown); 
bitmapGlowImages[1] = BitmapFactory.decodeResource(context.getResources(), R.drawable.blackkeydown);
bitmapGlowImages[2] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keyddown);
bitmapGlowImages[3] = BitmapFactory.decodeResource(context.getResources(), R.drawable.blackkeydown);
bitmapGlowImages[4] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keyedown);
bitmapGlowImages[5] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keycdown); 
bitmapGlowImages[6] = BitmapFactory.decodeResource(context.getResources(), R.drawable.blackkeydown);
bitmapGlowImages[7] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keyddown);
bitmapGlowImages[8] = BitmapFactory.decodeResource(context.getResources(), R.drawable.blackkeydown);
bitmapGlowImages[9] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keyddown);
bitmapGlowImages[10] = BitmapFactory.decodeResource(context.getResources(), R.drawable.blackkeydown);
bitmapGlowImages[11] = BitmapFactory.decodeResource(context.getResources(), R.drawable.keyedown);

в этом классе также запускается отдельный поток для рисования нажатых клавиш: с canvas.drawBitmap(bitmap, null, destRect, null). Наконец, когда вызывается onDestroy, вызывается мой метод recycleBitmaps()

public void recycleBitmaps() {
        if(bitmapKeyboard != null) {
            bitmapKeyboard.recycle();
            bitmapKeyboard = null;
            for(int i = 0; i < bitmapGlowImages.length; i++) {
                bitmapGlowImages[i].recycle();
                bitmapGlowImages[i] = null;
            }
            System.gc();
        }
}

Вот и все. И каждый раз в альбомной ориентации я добавляю свой SurfaceView к моему родительскому представлению в моем альбомном макете, а в портретном я снова удаляю его и загружаю свой портретный макет. Я делаю это в onConfigurationChanged(), потому что я сам обрабатываю изменения ориентации, поэтому приложение не уничтожается и создается каждый раз, когда вы меняете ориентацию устройства.

person pawlinsky    schedule 14.02.2013
comment
хорошо, возможно, что сейчас приложение не вылетает. Я вращал устройства примерно 20-30 раз. после 6-7 оборотов он по-прежнему выделяет больше памяти в куче (но теперь только 300-400 КБ). Когда размер кучи был достигнут, он зависал раньше, и теперь он только увеличивает размер кучи. Я скопировал файлы png во все доступные папки (mdpi, ldpi, xhdpi, hdpi). Но проблема все равно существует ... Я думаю, что это связано с масштабированием изображения ldpi, hdpi и т. Д. - person pawlinsky; 14.02.2013