Listview показывает неправильные изображения - PullRequest
4 голосов
/ 21 мая 2011

У меня есть ListView с ArrayAdapter, содержащий строки с изображением и строкой.Это работало нормально, пока я не решил, что загрузка изображений должна была быть медленной, поэтому я не мог загрузить изображения перед отображением списка.Поэтому я начал загружать изображения в отдельном потоке, используя AsyncTask.

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

Есть идеи, что я делаю неправильно?

public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        ImageView imageView;
        TextView textView;
        if (v == null) {
            LayoutInflater vi = (LayoutInflater) getContext().getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.drink_list_row, null);
        }

        Drink drink = allItems.get(position);
        if (drink != null && v != null) {
            imageView = (ImageView) v.findViewById(R.id.picture);
            textView = (TextView) v.findViewById(R.id.drinkName);
            imageView.setVisibility(View.GONE);
            loadImageBitmap(drink, imageView);
            textView.setText(drink.getName());

            if (subItems != null && subItems.contains(drink)) {
                textView.setVisibility(View.VISIBLE);
                imageView.setVisibility(View.VISIBLE);
            } else {
                textView.setVisibility(View.GONE);
                imageView.setVisibility(View.GONE);
            }
        }
        return v;
    }

1 Ответ

5 голосов
/ 21 мая 2011

Проблема возникает из вашего convertView: это тот же единственный экземпляр, который используется по всему списку, поэтому, когда ваша асинхронная загрузка завершена, изображение изменяется, когда просмотр списка пытается нарисовать другой элемент, используя тот же convertView (или в этом случае его дочерний imageView).

painting position 1, uses placeholder, starts loading image 1 asynchronously
painting position 2, uses placeholder, starts loading image 2 asynchronously
image 1 loading is complete, calling setImageBitmap on imageView
painting position 3, uses image 1, starts loading image 3 asynchronously
etc.

Что вы можете сделать, так это сохранить кэш растровых изображений в listadapter. Примерно так:

private Bitmap[] bitmapList;
private Bitmap bitmapPlaceholder;  

private void initBitmapListWithPlaceholders(){ 
// call this whenever the list size changes
// you can also use a list or a map or whatever so you 
// don't need to drop all the previously loaded bitmap whenever 
// the list contents are modified
    int count = getListCount();
    bitmapList = new Bitmap[count];
    for(int i=0;i<count;i++){
         bitmapList[i]=bitmapPlaceholder
    }
}

private void onBitmapLoaded(int position, Bitmap bmp){
// this is your callback when the load async is done
    bitmapList[position] = bmp;
}

public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    ImageView imageView;
    TextView textView;
    if (v == null) {
        LayoutInflater vi = (LayoutInflater) getContext().getSystemService(
                Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.drink_list_row, null);
    }

    Drink drink = allItems.get(position);
    if (drink != null && v != null) {
        imageView = (ImageView) v.findViewById(R.id.picture);
        textView = (TextView) v.findViewById(R.id.drinkName);
        imageView.setVisibility(View.GONE);
        imageView.setImageBitmap(bitmapList[position]);
        loadImageBitmap(drink, position); // this should call onBitmapLoaded(int position, Bitmap bmp) when finished to update the bitmapList and replace the placeholder
        textView.setText(drink.getName());

        if (subItems != null && subItems.contains(drink)) {
            textView.setVisibility(View.VISIBLE);
            imageView.setVisibility(View.VISIBLE);
        } else {
            textView.setVisibility(View.GONE);
            imageView.setVisibility(View.GONE);
        }
    }
    return v;
}
...