java - ListView 中的图像混合在一起

标签 java android listview android-listview android-asynctask

我正在开发一个聊天应用程序,我在其中实现了图像发送。因此,如果没有图像,一切都会正常。但现在我在显示发送/接收的图像时遇到问题。为此,我所做的是首先下载图像并将其保存在外部存储中。我的想法是简单地获取位图并将其设置在 getView 方法的 imageview 中。获取图像并显示没有任何问题,但 ListView 破坏了一切。

这是我的代码-

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;

问题是什么-

ListView 显示,但图像显示在随机 ListView 项目中。我针对此类问题进行了很多搜索,尝试过,但仍然没有成功。 asynctask 代码来自 Google-Use A Background Thread. 。正如您从上面看到的,我没有设置任何 holder.mMsg.setText(msg); 但每当显示图像时,它们仍然伴随着一条消息,这是不可取的。显示图像时滚动也有点滞后。我见过很多消息应用程序,它们都运行得非常流畅,而且项目从来不会混淆。那么他们用什么。另外,在谷歌搜索这个问题时,一个答案建议我们应该删除 converView if else 然后一切都会好起来的。但这会带来我不想要的性能问题。

所以我的问题是我应该做什么? Hangouts、bbm、whatsapp 等聊天应用是如何顺利实现这一目标的?

编辑

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

像这样-我滚动直到图像消息,它们被显示。然后我再次滚动,现在图像显示在其他 ListView 项目中。我的猜测是,相同的 View (最初保存图像)现在被其他人使用,但图像保留在那里。我该如何解决这个问题?并使 ListView 像 IM 应用程序一样平滑(即使是图像)?

最佳答案

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

我会使用 Picasso 避免问题并让其他人处理您的问题。

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

  1. 缓存,以避免发送对同一图像的多个请求,即使我内存中已经有他的图像
  2. 我发送 WeakReference<>到 Asynctask,因此完成后检查 ImageView 是否仍然有效并将位图放入其中。更新缓存。
  3. (针对我)由于有时我可能会遇到联系人没有照片的情况,我只是创建了另一个列表,其中包含所有没有照片的用户(所以我不会尝试下载它)
  4. 每次调用 .getview 时,都会检查图像是否在缓存内,如果在缓存内,则直接放入图像,或者启动异步任务。

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

如果您看到,它可能会在加载时显示另一张图片而不是用户照片,因此我设置了一张虚拟图片而不是旧照片。

这不是最好的实现,但它向您表明,自己实现并正确执行它可能非常困难。

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

关于java - ListView 中的图像混合在一起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24515555/

相关文章:

java - 测试需要模拟成员方法并使用 PowerMockito 抑制单例构造函数的静态方法

java - Maven 未在多模块项目中通过 Eclipse 运行测试

android - 如何根据 ScrollView 中的项目设置 ListView 高度

android - 如何将所选项目从 ListActivity 返回到另一个 Activity?

java - 导入的数据仅显示在 JTable (Java) 的第一列中

java - 将非 Maven 项目转换为 Maven

java - 如何将 'cast' 转换为通用对象并使用通用参数执行方法

java - 如何使用 Java 设置 columnWeight

java - Android - 使用键查询节点 (Firebase)

java - 如何将 ListView 项添加到整个其他 ListView