Переработка растровых изображений Android ICS

Я использовал следующий код в onDestroy для повторного использования большого растрового изображения, чтобы быстро восстановить память. Если я этого не сделаю, приложение вылетит с ошибкой OutOfMemory после нескольких поворотов экрана. Андроид плохо справляется с памятью.

ImageView imgBG = (ImageView)findViewById(R.id.mainBG);
if (imgBG != null)
{
    ((BitmapDrawable)imgBG.getDrawable()).getBitmap().recycle();
    imgBG.setImageDrawable(null);
}
System.gc();

К сожалению, в ICS все изменилось. Они начали кешировать ресурсы, а переработка растрового изображения фактически перерабатывает растровое изображение в кеше. Android недостаточно умен, чтобы понять это, и он пытается использовать переработанное растровое изображение в будущем, что приводит к следующему:

java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@40f44390
at android.graphics.Canvas.throwIfRecycled(Canvas.java:1047)
at android.graphics.Canvas.drawBitmap(Canvas.java:1151)
at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:400)
at android.widget.ImageView.onDraw(ImageView.java:973)
at android.view.View.draw(View.java:11014)
at android.view.ViewGroup.drawChild(ViewGroup.java:3186)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2788)
at android.view.ViewGroup.drawChild(ViewGroup.java:3184)
[...]

Так вот проблема. Если я его переработаю, он вылетит на ICS. Если я этого не сделаю, у приложения закончится память. Что я должен делать? Как правильно освободить память, что реально работает?


person Sebastian Nowak    schedule 21.07.2012    source источник
comment
Я думаю такое кеширование (расшаривание) сделано еще в Андроиде 2.3, возможно просто не так агрессивно. Однако, насколько мне известно, он делает это только для растровых изображений, определенных XML. Вы пытались загрузить свое растровое изображение через decodeBitmap, а затем установить для представления? Надеюсь, в этом случае Android не будет использовать системный кеш. Дайте мне знать, как это происходит, так как у меня тоже была похожая проблема, и я с нетерпением жду вашего опыта.   -  person Thomas Calc    schedule 26.07.2012


Ответы (1)


Попробуй это:

ImageView imgBG = (ImageView)findViewById(R.id.mainBG);
if (imgBG != null)
{
    BitmapDrawable drawable = ((BitmapDrawable)imgBG.getDrawable()).getBitmap();
    imgBG.setImageDrawable(null);
    drawable.recycle();
}
System.gc();
person Superbiji    schedule 21.07.2012
comment
Это именно то, что я делаю, и мой вопрос объясняет, почему этот подход теперь НЕПРАВИЛЬНЫЙ. Вы не можете повторно использовать растровое изображение. - person Sebastian Nowak; 21.07.2012
comment
в соответствии с выброшенным исключением: может быть, есть другой поток для обновления пользовательского интерфейса? который запрашивает переработанное растровое изображение. Вот почему я сначала сохраняю растровое изображение для рисования, устанавливаю значение null, а затем перерабатываю. - person Superbiji; 02.08.2012
comment
Перестаньте гадать и просто прочитайте мой вопрос. Это объясняет, когда recycle() терпит неудачу и почему такой подход неверен. - person Sebastian Nowak; 02.08.2012