图像在listview中混淆了

时间:2014-07-01 16:50:59

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

我正在开发聊天应用,我已经实施了图片发送。所以没有图像一切正常。但现在我正面临发送/接收显示图像的问题。为此我首先下载了图像并将其保存在外部存储器中。我的想法很简单,就是在imageview方法的getView中设置位图。获取图像和显示没有错,但列表视图遗留下来。

这是我的代码 -

ListView getView()

ViewHolder holder = null;
if(convertView == null ){

   convertView = inflater.inflate(R.layout.chat_list, null);           
   holder = new ViewHolder();
   holder.mMsg = (TextView) convertView.findViewById(R.id.text);
   holder.mDate = (TextView) convertView.findViewById(R.id.text1);
   holder.mLinLay=(LinearLayout) convertView.findViewById(R.id.linSide1);
   holder.mRelLay=(RelativeLayout) convertView.findViewById(R.id.relSide);
   holder.img=(ImageView)convertView.findViewById(R.id.image);
   holder.progCircle=(ProgressBar)convertView.findViewById(R.id.pbHeaderProgress);
   convertView.setTag(holder);

} else{

   holder = (ViewHolder) convertView.getTag();

}

holder.position=position;
holder.img.setTag(position+"img");
HashMap<String, String> hm = list.get(position);
String date=hm.get("date");
long l = Long.parseLong(date);
long unixTime = System.currentTimeMillis();
CharSequence datedate=DateUtils.getRelativeTimeSpanString(l, unixTime, 1);
String status = hm.get("status");
String who = hm.get("who");

if(hm.get("message").contains("[[pic_message]]"))
{

   String picName=hm.get("message").replace("[[pic_message]]", "");
   final String picPath1=Environment.getExternalStorageDirectory()+"/App/sent_pics/"+picName+".jpg";
   File file = new File(picPath);
   if(file.exists()) 
   {

      new AsyncTask<ViewHolder, Void, Bitmap>() {
         private ViewHolder v;
         Bitmap bm;
         @Override
         protected Bitmap doInBackground(ViewHolder... params) {
             v = params[0];
             bm = decodeSampledBitmapFromResource(picPath1,100,100);
             return bm;
         }

         @Override
         protected void onPostExecute(Bitmap result) {
            super.onPostExecute(result);
            if (v.img.getTag().equals(position+"img")) {
               v.img.setImageBitmap(result);
            }
         }
      }.execute(holder);
    }else{ 
      holder.img.setImageBitmap(null);
    }
 }else{
    holder.img.setImageBitmap(null);
    Spannable msg  =getSmiledText(getApplicationContext(),hm.get("message"));
    holder.mMsg.setText(msg);
 }
 holder.mDate.setText(datedate);

 return convertView;

问题是什么 -

列表视图显示,但图像显示在随机列表视图项。我经常搜索这类问题,尝试过但却没有运气。 asyntask代码来自 Google- Use A Background Thread. 。从上面看,我没有设置任何holder.mMsg.setText(msg);,但是无论何时显示图像,它们都伴随着一个msg,这是不可取的。当显示图像时,滚动也是类似的延迟。我见过许多消息传递应用程序,它们运行得非常顺利,而且这些项目永远不会混淆。那么他们使用了什么。另外,在谷歌搜索这个问题时,一个答案建议我们应该删除converView if else,然后一切都会好的。但那会产生我不想要的性能问题。

所以我的问题是我该怎么办?聊天应用如Hangouts,bbm,whatsapp如何顺利实现这一目标?

修改

图片显示没有问题,但主要问题是它们以随机顺序显示

像这样 - 我滚动到图像信息,它们会显示出来。然后我再次滚动,现在图像显示在其他列表视图项目中。我的猜测是,相同的视图(原来一直保持图像)现在被其他人使用,但图像保留在那里。我该如何解决这个问题?并使列表视图像IM应用程序一样流畅(即使是图像)?

3 个答案:

答案 0 :(得分:3)

这是因为Android ListView重用了Views,所以当你的Asynctask执行donInBackground时,用户已经在做其他事情了,而你的代码对此一无所知。 (所以它会把图像放在一起)

我会使用Picasso来避免这个问题,让其他人来处理您的问题。

我使用以下方法在我的应用程序(联系电话)中处理了这个问题:

  1. 缓存,以避免发送同一图像的多个请求,即使我已经在内存中有他的图像
  2. 我向Asynctask发送WeakReference<>,以便在完成后检查ImageView是否仍然有效并将位图放入其中。更新缓存。
  3. (特定于我)因为有时我可能会发生一个联系人没有照片我只是创建了一个没有照片的所有用户的另一个列表(所以我不想尝试下载)
  4. 每当调用.getview时,检查图像是否在缓存中,如果它在缓存中直接放入,或者启动asynctask。

    Bitmap bitmap = cache.get(number);
    if (bitmap == null) {
        Log.d(TAG, "I will download image for " + name + ".");
        // i set a dummy image to avoid to show the wrong picture
        holder.contactPhoto.setImageResource(R.drawable.ic_action_person);
        loadUserProfilePhoto(number, holder.contactPhoto);
    }
    else {
        // show it directly
        Log.d(TAG, "I already have " + name + " in cache.");
        holder.contactPhoto.setImageBitmap(bitmap);
    }
    
  5. 如果你看到,它可能会显示另一张图片而不是用户照片,而它仍在加载它,所以我设置了一张虚拟照片而不是旧照片。

    这不是最好的实施方式,但它告诉您,自己实施并正确执行它可能非常困难。

    阅读Picasso文档并了解它如何在您的代码中实现它(它很简单,它只是一行。)

答案 1 :(得分:1)

问题在于listview不断刷新它。

所以你的所有代码都很好,但只需在holder.img中设置默认图像,而不是将其设为null holder.img.setImageBitmap(null);

也可能处于异步状态,您需要在加载图像时设置default_image。

答案 2 :(得分:0)

如果您想要动态显示图像,我认为您应该使用SurfaceView。它速度更快,刷新率更高。我制作了一个视频流应用程序,我尝试在ImageView上显示每个视频帧,但失败了。但是当我尝试使用SurfaceVIew时,效果很好。