我正在开发一个聊天应用程序,我在其中实现了图像发送。因此,如果没有图像,一切都会正常。但现在我在显示发送/接收的图像时遇到问题。为此,我所做的是首先下载图像并将其保存在外部存储中。我的想法是简单地获取位图并将其设置在 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
避免问题并让其他人处理您的问题。
我在我的应用程序(联系电话)中使用以下方法处理了这个问题:
- 缓存,以避免发送对同一图像的多个请求,即使我内存中已经有他的图像
- 我发送
WeakReference<>
到 Asynctask,因此完成后检查 ImageView 是否仍然有效并将位图放入其中。更新缓存。 - (针对我)由于有时我可能会遇到联系人没有照片的情况,我只是创建了另一个列表,其中包含所有没有照片的用户(所以我不会尝试下载它)
每次调用 .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/