setImageBitmap в BaseAdapter#getView не обновляет ImageView

У меня есть приложение, которое загружает кучу изображений в фоновом потоке. По мере загрузки каждого значка я добавляю его в список ArrayList в своем пользовательском адаптере, который является подклассом BaseAdapter. Каждая строка в ListView, которая использует BaseAdapter, имеет ImageView. В getView я делаю следующее.

public View getView(int position, View convertView, ViewGroup parent) {
    final MyCustomImageClass imageObject = data.get(position);
    View vi = convertView;

    if(convertView==null) {
        vi = inflater.inflate(R.layout.list_row, null);
    }

    ImageView thumbnail = (ImageView)vi.findViewById(R.id.list_image);
    File appDir = new File(Utils.getAppFilesDir() +"");
    File imageFolder = new File(appDir, imageObject.getImageFolderName());
    File imageDir = new File(imageFolder, imageObject.getIconFilename());
    Log.e("myapp", "row image dir: " + imageDir.toString());
    if(imageDir.exists()) {
        Bitmap imageBitmap = BitmapFactory.decodeFile(imageDir.toString());
        thumbnail.setImageBitmap(imageBitmap);
    }
    thumbnail.invalidate();
}

Но я вижу, что thumbnail повторно использует старые изображения. Например, первые несколько строк будут иметь одно и то же миниатюрное изображение, хотя я вижу для них другой путь в logcat.

Как сообщить строке в ListView, что в ее ImageView есть новое растровое изображение?


person user5243421    schedule 27.01.2013    source источник


Ответы (2)


Каждая строка в ListView будет переработана, поэтому, когда одна строка исчезнет с экрана, следующая будет повторно использовать этот контейнер. Вы, вероятно, не удовлетворяете оператору if в новом обновленном ImageView, поэтому изображение не установлено на то, что вы хотите, поэтому оно просто повторно использует старое. Убедитесь, что ваш imageDir.exists() завершится успешно, чтобы обеспечить правильное обновление нового представления. Кроме того, я не думаю, что есть какая-то причина называть недействительным.

Редактировать: я понимаю, почему вы сейчас звоните invalidate(), но это все еще не нужно. Я бы предложил использовать изображение по умолчанию для ImageView, например, поставляемое Android, а затем сделать что-то вроде этого:

if(imageBitmap != null)
  thumbnail.setImageBitmap(imageBitmap);
else
  thumbnail.setImageDrawable(R.drawable.content_picture);

где R.drawable.content_picture — это изображение по умолчанию «нет изображения для отображения», а также оно определено для ImageView в XML-файле.

Наконец, вы должны рассмотреть возможность использования ViewHolder для ускорения рендеринга ListView. Вот пример: Как реализовать держатель представления?

Если что-то, что я сказал здесь, не имеет смысла, просто попросите разъяснений.

person Matt    schedule 27.01.2013
comment
И обязательно следуйте совету Krylez по загрузке изображений из потока пользовательского интерфейса! - person Matt; 27.01.2013

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

В качестве примечания: вам действительно не следует читать диск или декодировать растровые изображения в потоке пользовательского интерфейса. Метод getView() должен надежно возвращаться очень быстро, что исключает выполнение какой-либо реальной работы. Ознакомьтесь с руководством разработчика, чтобы получить полезные советы по работе с растровыми изображениями:

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

person Krylez    schedule 27.01.2013