在listview中加载图像时加载错误的图像

时间:2012-07-26 23:23:51

标签: java android multithreading android-listview android-asynctask

我见过这样的几个问题,但我似乎遇到了一个稍微不同的问题。所以我想我会在这里问别人。

我有一个带有textview和imageview的自定义列表视图。我正在使用异步任务加载图像,然后在后执行方法中将图像设置为imageview。我的图像加载正常,但有些图像被其他图像替换。但是在完成所有图像加载后,每个图像视图都具有正确的图像。我似乎无法弄清楚为什么我有这个问题。

这是我的适配器和异步任务类。任何和所有的帮助将不胜感激。

编辑我现在正在添加一个标记(标记是进入imageviews各个textview的文本),在我的帖子执行中,我正在检查标记是否等于textview中的文本。我仍然遇到和以前一样的问题。

这是我的Adapter类:

public class CustomListAdapter extends ArrayAdapter<CustomList> {

    Context context;
    int layoutResourceId;
    LinkedList<CustomList> data = null;
    LinkedList<String> title_list = new LinkedList();

    LoadImage l;
    CustomList cl;
    ProgressBar pb;
    HashMap <String, Bitmap> bitmap = new HashMap<String, Bitmap>();







    public CustomListAdapter(Context context, int layoutResourceId, LinkedList<CustomList> data, LinkedList<Bitmap> bitmap_list) {
        super(context, layoutResourceId, data);
        // TODO Auto-generated constructor stub

        this.context = context;
        this.layoutResourceId = layoutResourceId;
        this.data = data;

    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub

        View row = convertView;
        CustomListHolder holder = null;




        if(row == null){
            LayoutInflater inflater = ((Activity)context).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);
            holder = new CustomListHolder();

            holder.text = (TextView)row.findViewById(R.id.txtTitle);
            holder.thumbnail = (ImageView)row.findViewById(R.id.imgIcon);
            holder.pb = (ProgressBar)row.findViewById(R.id.progressBar1);

            row.setTag(R.id.id0, holder);


            cl = data.get(position);
            holder.text.setText(cl.title);
            holder.thumbnail.setImageResource(R.drawable.icon);
            holder.pb.setVisibility(View.VISIBLE);


            row.setTag(R.id.id1,new String(cl.title));
            LoadImage li = new LoadImage(context, holder.thumbnail, cl.icon,cl.title, bitmap,holder.pb,row);
            li.execute(cl.icon);        

        }

        else{
            Log.e("Row not null","Inside");
            holder = (CustomListHolder)row.getTag(R.id.id0);
            //row.getK
            cl = data.get(position);        
            holder.text.setText(cl.title);
            holder.thumbnail.setImageResource(R.drawable.icon);
            holder.pb.setVisibility(View.VISIBLE);
            if((Bitmap) bitmap.get(cl.title) == null){
                row.setTag(R.id.id1,new String(cl.title));
              LoadImage li = new LoadImage(context, holder.thumbnail, cl.icon,cl.title, bitmap,holder.pb,row);
                li.execute(cl.icon); 


            }
            else {
                holder.thumbnail.setImageBitmap((Bitmap) bitmap.get(cl.title));
                holder.pb.setVisibility(View.GONE);
            }



        }   



        return row;


    }

    static class CustomListHolder
    {
        ImageView thumbnail;
        TextView text;
        ProgressBar pb;
    }


}

这是我的异步任务类:

公共类LoadImage扩展了AsyncTask {

Context callingContext = null;
ImageView view;
String bits;
public  ProgressBar pb;
HashMap<String, Bitmap> bitmap; 
String url;
String text;
View row;



public LoadImage(Context c, ImageView view, String bits, String text, HashMap<String, Bitmap> bitmap, ProgressBar pb, View row){

    this.view = view;
    this.bits = bits; // url for image
    this.callingContext = c;
    this.bitmap = bitmap; //hashmap
    this.text = text;// title text
    this.pb = pb;
    this.row = row;

}



public Bitmap getBitmap(String data){

    Bitmap bitmap;
    BitmapFactory.Options bmOptions;
    bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    Log.e("getBitmap",text);

    try {
        bitmap=null;
        InputStream is=new URL(data).openStream();
        BitmapFactory.decodeStream(is, null, bmOptions);
        is.close();
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = 10;
        is = new URL(data).openStream();
        bitmap = BitmapFactory.decodeStream(is, null, o2);

        bitmap = Bitmap.createScaledBitmap(bitmap, 60, 60, true);
        is.close();
        this.bitmap.put(text,bitmap);
        return bitmap;
    } catch (Exception ex){
        Log.e("Debug", ex.getMessage());
       return null;
    }

}


@Override
protected Bitmap doInBackground(String... arg0) {
    // TODO Auto-generated method stub
    Log.e("do In Bg",text);
    Bitmap b = null;    

    if((Bitmap)bitmap.get(text) == null)
      b = getBitmap(bits);
    else 
      b =(Bitmap)bitmap.get(text);

        return b;  
}



@Override
protected void onPostExecute(Bitmap result) {
    // TODO Auto-generated method stub
    super.onPostExecute(result);
        if(row.getTag(R.id.id1).equals(text)){
            view.setImageBitmap((Bitmap)bitmap.get(text));
            pb.setVisibility(View.GONE);
        }




}   

}

CustomList是一个包含2个字符串图标和标题的类。 icon是图像的url,title是textview的文本。

1 个答案:

答案 0 :(得分:4)

我确定@Krylez会告诉你同样的事情:在ListView中,你的行被回收了。这是covertView为您提供的行,您执行行== null检查。如果您的屏幕一次显示10行,则内存中可能包含大约11到12行。当你滚动并且一行不在视图中时,它会被保存在内存中,然后用旧的东西给你回复。

假设您有单元格1 ...您要求位图1.然后用户将其滚出视图并将其作为位图12再循环。现在位图1任务完成并绘制它,因为对象引用仍然完好无损(从未被摧毁过)。所以你会看到出现错误图像的效果。

我在iOS项目上使用了一个简单的修复:使用对象标签。让我解释一下:

当您启动LoadImage任务时,使用唯一ID标记您的行,您可以识别位图及其与...的位置关系。

row.setTag(new Integer(ID_THAT_IDENTIFIES_ROW_AND_BITMAP_RELATIONSHIP))

当您在异步任务中执行onPostExecute()时,请检查此标识符是否已更改。如果您当前的位图不再匹配,请不要做任何事情,因为可能还有其他任务正在等待填充它。

我希望有所帮助!