列表视图显示错误的图像视图、图像、错误、列表

2023-09-13 01:16:26 作者:毅力坚强帝

我有一个ArrayAdapter行持用图像和字符串一个ListView。这工作正常,直到我决定图像的加载是慢,所以我显示列表之前,无法加载图像。于是我开始加载图像在一个单独的线程中使用的AsyncTask

我很高兴,结果,直到我开始滚动列表。错误的图像加载,它看起来并不像它的形象得到了一段时间后的问题。如果我试图问题的情况真的不好对列表进行排序,并没有任何图像在右边行。

什么我做错了任何想法?

 公开查看getView(INT位置,查看convertView,ViewGroup中父){
        视图V = convertView;
        ImageView的ImageView的;
        的TextView TextView的;
        如果(V == NULL){
            LayoutInflater VI =(LayoutInflater)的getContext()。getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE);
            V = vi.inflate(R.layout.drink_list_row,NULL);
        }

        喝饮料= allItems.get(位置);
        如果(饮料= NULL和放大器;!&安培;!V = NULL){
            ImageView的=(ImageView的)v.findViewById(R.id.picture);
            TextView的=(的TextView)v.findViewById(R.id.drinkName);
            imageView.setVisibility(View.GONE);
            loadImageBitmap(饮料,ImageView的);
            textView.setText(drink.getName());

            如果(子项目= NULL和放大器;!&安培; subItems.contains(饮料)){
                textView.setVisibility(View.VISIBLE);
                imageView.setVisibility(View.VISIBLE);
            } 其他 {
                textView.setVisibility(View.GONE);
                imageView.setVisibility(View.GONE);
            }
        }
        返回伏;
    }
 

解决方案

这个问题是从convertView:它是用于在整个列表中的同一个实例,因此,当你的异步加载完成后,图像被改变时,列表视图试图描绘使用相同convertView不同的项目(或在这种情况下,它的子ImageView的)。

 绘画位置1,使用占位符,开始异步加载图像1
绘画位置2,使用占位符,开始加载图像2异步
图片1加载完成后,呼吁setImageBitmap上的ImageView
绘画位置3,利用图像1,开始加载图像3异步
等等
 

你可以做的虽然是守位图缓存在listadapter。事情是这样的:

 私人位图[] bitmapList;
私人位图bitmapPlaceholder;

私人无效initBitmapListWithPlaceholders(){
//调用这个每当列表的大小变化
//你也可以使用一个列表或地图或什么,所以你
//不需要删除所有previously加载位图时
//列表内容被修改
    诠释计数= getListCount();
    bitmapList =新的位图[统计]
    的for(int i = 0; I<计数;我++){
         bitmapList [我] = bitmapPlaceholder
    }
}

私人无效onBitmapLoaded(INT位置,BMP位图){
//这是您的回调,当负载异步完成
    bitmapList [位置] = BMP;
}

公共查看getView(INT位置,查看convertView,ViewGroup中父){
    视图V = convertView;
    ImageView的ImageView的;
    的TextView TextView的;
    如果(V == NULL){
        LayoutInflater VI =(LayoutInflater)的getContext()。getSystemService(
                Context.LAYOUT_INFLATER_SERVICE);
        V = vi.inflate(R.layout.drink_list_row,NULL);
    }

    喝饮料= allItems.get(位置);
    如果(饮料= NULL和放大器;!&安培;!V = NULL){
        ImageView的=(ImageView的)v.findViewById(R.id.picture);
        TextView的=(的TextView)v.findViewById(R.id.drinkName);
        imageView.setVisibility(View.GONE);
        imageView.setImageBitmap(bitmapList [位置]);
        loadImageBitmap(饮料,位置); //这个应该叫onBitmapLoaded(INT位置,BMP位图),当完成更新bitmapList和替换占位符
        textView.setText(drink.getName());

        如果(子项目= NULL和放大器;!&安培; subItems.contains(饮料)){
            textView.setVisibility(View.VISIBLE);
            imageView.setVisibility(View.VISIBLE);
        } 其他 {
            textView.setVisibility(View.GONE);
            imageView.setVisibility(View.GONE);
        }
    }
    返回伏;
}
 
组织视图 用户列表显示错位

I have a ListView with an ArrayAdapter holding rows with a Image and a String. This worked fine until I decided that the loading of the images was to slow so I could not load the images before showing the list. So I started to load the images in a separate thread using an AsyncTask.

I was very happy with the result until I started to scroll the list. Wrong images was loaded and it doesn't look like it is a question of the image getting a while later. If I attempt to sort the list the problem goes really bad and none of the images is on the right row.

Any ideas of what I'm doing wrong?

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;
    }

解决方案

The problem comes from your convertView: it's the same single instance that is used throughout the list, so when your asynchronous loading is complete, the image is changed when the listview is trying to paint a different item using the same convertView (or in that case, its child 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.

What you can do though is keep a cache of Bitmaps in the listadapter. Something like this:

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;
}