在ListView中遇到异步图像加载问题

时间:2015-02-06 03:48:36

标签: android listview parse-platform android-arrayadapter

对我来说这是一个非常大的麻烦,我已经在这方面工作了几个小时,而且没有任何线索!

我在ListView中遇到异步图像加载问题。

我正在使用Parse.com作为我的应用程序的Backend,我正在从Parse.com类中检索消息及其图像。

一切正常,当我向上/向下滚动,或再次加载列表视图,图片混合,所有图片重新加载另一个订单,几秒后他们将按我的要求订购,但这是一个很大的我的问题。

我认为这种情况正在发生,因为我正在使用这样的类来上传图像

private class DownloadImageTask extends AsyncTask<String, Void, Bitmap>

无论如何,我的适配器类如下:

public class adapterview extends ArrayAdapter<Message> {
Bitmap image;
public adapterview(Context context, ArrayList<Message> Messages) {
   super(context, 0, Messages);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
   // Get the data item for this position
   final Message m = getItem(position);    
   // Check if an existing view is being reused, otherwise inflate the view
   if (convertView == null) {
      convertView = LayoutInflater.from(getContext()).inflate(R.layout.custom2, parent, false);
   }

   TextView message = (TextView) convertView.findViewById(R.id.message);
   TextView date = (TextView) convertView.findViewById(R.id.date);
   TextView user = (TextView) convertView.findViewById(R.id.user);
   message.setText(m.getMessage());
   user.setText(m.getUser()); 
   new DownloadImageTask((ImageView) convertView.findViewById(R.id.imageView1))
   .execute(m.getImage());

   return convertView;


}


 private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
  ImageView bmImage;

  public DownloadImageTask(ImageView bmImage) {
      this.bmImage = bmImage;
  }

  protected Bitmap doInBackground(String... urls) {
      String urldisplay = urls[0];
      Bitmap mIcon11 = null;
      try {
        InputStream in = new java.net.URL(urldisplay).openStream();
        mIcon11 = BitmapFactory.decodeStream(in);
      } catch (Exception e) {
          Log.e("Error", e.getMessage());
          e.printStackTrace();
      }
      return mIcon11;
  }

  protected void onPostExecute(Bitmap result) {
      bmImage.setImageBitmap(result);
  }
}

这是我的消息类:

public class Message {

String message;
String user;
String phone;
String image;
String date;

public String getDate() {
    return date;
}

public void setDate(String date) {
    this.date = date;
}

public String getImage() {
    return image;
}

public void setImage(String image) {
    this.image = image;
}

public String getPhone() {
    return phone;
}

public void setPhone(String phone) {
    this.phone = phone;
}

public String getUser() {
    return user;
}

public void setUser(String user) {
    this.user = user;
}

public String getMessage() {
    return message;
}

public void setMessage(String message) {
    this.message = message;
}
}

以及我如何将项目添加到我的列表中:

contacts c = new contacts();
            c.setName(object.get("name").toString());
            c.setNumero(object.get("phone").toString());
            ParseFile image = (ParseFile)object.get("Profil");
            c.setProfil(image.getUrl());
            messagelist.addcontact(c);

这是我从MainActivity填充列表视图的代码:

        adapterview adapter = new adapterview(MainActivity.this, (ArrayList<Message>) messagelist);
    list.setAdapter(adapter);

这是我向下滚动然后向上滚动的两个屏幕截图,以便第一个listItem的图片发生变化!!无缘无故,然后在几秒钟后回到正常画面。

enter image description here

enter image description here

如果您可以就如何将图像从URL上传到ImageView建议一种新方法,那就太棒了。

6 个答案:

答案 0 :(得分:2)

我认为你正在观察的是由于listview的viewholder模式。你正在尝试通过getview()中的aysnctask下载并将图像设置为图像,但是当你向上或向下滚动时,视图会被回收再次当你再次转到那个位置你的getview调用那个位置,所以再次执行asynctask并再次在imageview中下载图像因此你看到延迟,我建议你使用 PICASSO libraray对于图像下载非常有效并且您的图像缓存在这里也是链接http://square.github.io/picasso/或使用 Glide ,现在谷歌正式推荐,这里是github链接Glide

答案 1 :(得分:1)

上次我也使用手动下载联系人的头像,但这很糟糕。 我认为你的问题是:

  • 下载头像,然后设置为ImageView
  • 但是,您正在使用ViewHolder模式,因此新下载的头像将设置为多个imageview&gt;指定联系人的错误头像(这仅在下载所有头像时运行良好)

首先,检查Universal Image Loader库,将头像URL设置为视图,它会自动下载,将你的头像缓存到内存中。

如果您仍然出现错误的头像问题,请在此处发帖。

答案 2 :(得分:1)

  

图片混合,所有图片以其他顺序重新加载,和   几秒钟后,他们会按照我的要求订购

由于AsyncTask方法中getView没有查看持有人模式而发生这种奇怪的行为。

为了避免再次渲染已经渲染的缩略图,并在滚动时使用View Holder模式从listview中的网络加载新图像。

请参阅以下有用的教程,了解如何使用View Holder创建具有良好滚动和加载性能的ListView:

Performance Tips for Android’s ListView

答案 3 :(得分:1)

这是因为ListView在滚动时回收视图,然后在调用异步任务下载图片并滚动时,下载完成但参考指向回收视图和一个或多个异步任务指向相同的观点。有一种方法可以避免这种情况,即在下载开始时以及在下载结束时,在绘制图像之前查看它是否正确,然后绘制图像。

您可以使用图片的网址标记视图,因为它是唯一的值。

在下载的preExecute中,您必须使用URL(字符串)标记ImageView。

imageView.setTag(url);

当任务完成并在绘制图像之前,恢复标记并检查它。

String tag = (String)imageView.getTag();
if(tag != null && tag.equals(url)){
    //Draw the image
} else {
    //Draw the placeholder or clean the ImageView
}

您可以使用ViewHolder模式升级ListView的性能,以及当Parse可以通过其API执行它时手动下载图像的原因,Parse方式和使用Cache策略,当您下载图像时自动缓存位图,当你再次询问下载时,只检索了缓存的结果。

干杯!

答案 4 :(得分:1)

我通过使用回收视图的onBindViewHolder

解决了这个问题
@Override
public void onBindViewHolder(final MyViewHolder viewHolder, int i) {
    CartsViewModel currentData = data.get(i);
    ParseFile image = currentData.getParseImage();
    if(image!=null){
        Log.d(TAG,"image not null. Downloading....");
        image.getDataInBackground(new GetDataCallback() {
            @Override
            public void done(byte[] bytes, ParseException e) {
                if(e==null){
                    Log.d(TAG,"donload finished");
                    Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                    viewHolder.cartImage.setImageBitmap(bmp);
                }else{
                    viewHolder.cartImage.setImageBitmap(null);
                }
            }else{
                viewHolder.cartImage.setImageBitmap(null);
            }
        });
    }
    viewHolder.cartName.setText(currentData.getCartName());
    viewHolder.cartAddress.setText(currentData.getCartAddress());
    viewHolder.rating.setText(currentData.getRating());
    viewHolder.reviewCount.setText(currentData.getReviewCount());

}

与parse方法的魅力相似。

答案 5 :(得分:0)

listview单元格布局xml文件是什么? 我认为Android无法确定listview的单元格大小。这会导致一些问题。 如果要使用异步加载图像,解决问题的一种方法是修复图像大小。例如

    <ImageView
        android:id="@+id/row_icon1"
        android:layout_width="60dip"
        android:layout_height="60dip"
        android:layout_gravity="center_vertical"
    />