"Невозможно нарисовать переработанные растровые изображения" при отображении растровых изображений в приложении Галерея, прикрепленных к адаптеру

В Android 4.1 a для меня, похоже, странная ошибка возникает в нашем приложении. В приложении пользовательский адаптер, расширяющий BaseAdapter, присоединяется к виджету "Галерея". При быстрой прокрутке слева направо и наоборот я получаю FC с сообщением об исключении:

java.lang.IllegalArgumentException: Невозможно нарисовать переработанное растровое изображение

Код метода getView (..) выглядит следующим образом:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder viewHolder;

    if (convertView == null){
        // View is not recycled. Inflate the layout.
        LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = vi.inflate(R.layout.gallery_image, parent, false);

        viewHolder = new ViewHolder();
        viewHolder.image = (ImageView) convertView.findViewById(R.id.gallery_image);

        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder)convertView.getTag();
        viewHolder.image.setImageDrawable(null);
    }

    imageLoader.displayImage(images.get(position).getFilename(),
            images.get(position).getUrlThumbnail(),
            viewHolder.image,
            Math.round(BitmapUtil.convertDpToPixel(400f, context)),
            Math.round(BitmapUtil.convertDpToPixel(400f, context)));

    return convertView;
}

Я предполагаю, что я должен игнорировать ImageView, но я не могу заставить его работать правильно. ImageLoader - (совершенно) простой класс для загрузки изображений - либо из LruCache, disk/sdcard, либо извлечения его удаленно.

Ответы

Ответ 1

Оказывается, эта ошибка вызвана вызовом oldBitmap.recycle() в методе entryRemoved(..) в моем классе, переопределяющем LruCache. Поскольку растровое изображение все еще может быть прикреплено к вызову ImageView recycle(), это вызовет проблемы.

Если я правильно понимаю: размер кеша LruCache будет установлен в его конструкторе. Когда количество элементов превышает этот размер, объекты будут иметь право на сбор мусора, что произойдет, когда растровое изображение больше не связано с ImageView.

В многочисленных примерах и учебниках по всему миру предлагается recycle() вызывать в entryRemoved(..), но из того, что я вижу, это неправильно.

Ответ 2

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

Освободите собственный объект, связанный с этим растровым изображением, и очистите ссылки на данные пикселя. Это не освободит пиксельные данные синхронно; он просто позволяет собирать мусор, если нет других ссылок. Растровое изображение отмечено как "мертвое", что означает выдает исключение, если вызывается getPixels() или setPixels(), и ничего не рисует. Эта операция не может быть отменена, поэтому она должна вызывается только в том случае, если вы уверены, что для битовая карта. Это расширенный вызов, и его обычно не нужно называть, так как нормальный процесс GC освободит эту память, когда нет больше ссылок на это растровое изображение.

Я предлагаю вам не перерабатывать Bitmap до этого момента, поскольку для него все еще используется. Поэтому перейдите в свой код, когда вы вызываете метод recycle(), а затем удаляете его.

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

public void disposeBitmap(Bitmap bitmap) {
        bitmap.recycle();
        bitmap = null;
}

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