Изображения, перепутанные в listview

#java #android #listview #android-listview #android-asynctask

#java #Android #listview #android-listview #android-asynctask

Вопрос:

Я разрабатываю приложение для чата, в котором я реализовал отправку изображений. Итак, без изображений все работает нормально. Но теперь я сталкиваюсь с проблемами при отображении изображений, которые отправлены / получены. Для этого я сначала загрузил изображение и сохранил его во внешнем хранилище. Моя идея заключалась в том, чтобы просто извлечь растровое изображение, установить его в методе imageview on getView . Ничего плохого в извлечении изображения и отображении, но 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. Я много искал такого рода проблемы, пробовал их, но все равно безуспешно. Код asyntask взят из Google- Используйте фоновый поток.. Как вы видите выше, я не устанавливал никаких holder.mMsg.setText(msg); , но все же всякий раз, когда изображения отображаются, они сопровождаются сообщением, что нежелательно. Также прокрутка немного отстает при отображении изображений. Я видел много приложений для обмена сообщениями, все они работают так гладко, и элементы никогда не перепутываются. Итак, что они используют.Кроме того, при поиске в Google этой проблемы в одном ответе предлагалось удалить converView if else , и тогда все будет хорошо. Но это приведет к проблемам с производительностью, которых я не хочу.

Итак, мой вопрос в том, что мне делать? Как приложения для чата, такие как hangouts, bbm, WhatsApp, достигают этого так гладко?

Редактировать

Картинки отображаются без проблем, но главная проблема заключается в том, что они воспроизводятся в случайном порядке.

Вот так — я прокручиваю до появления сообщения об изображении, они отображаются. Затем я снова прокручиваю, и теперь изображение отображается в другом элементе listview. Я предполагаю, что тот же вид (который изначально содержал изображение) теперь используется другими, но изображение остается там. Как я могу это исправить? И сделать listview плавным (даже с изображениями), как в приложениях обмена мгновенными сообщениями?

Ответ №1:

Это потому, что Android ListView повторно использует представления, поэтому, когда вы Asynctask выполняете donInBackground, пользователь уже делает что-то еще, и ваш код ничего об этом не знает. (Таким образом, он поместит изображение)

Я бы использовал Picasso , чтобы избежать проблемы и позволить кому-то другому справиться с вашей проблемой.

Я решил эту проблему в своем приложении (контактный телефон) с помощью:

  1. Кэш, чтобы избежать отправки нескольких запросов на одно и то же изображение, даже если у меня уже есть в памяти его изображение
  2. Я отправляю WeakReference<> в Asynctask, поэтому, когда это будет сделано, проверьте, является ли 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);
    }
      

Если вы видите, может случиться так, что вместо фотографии пользователя будет отображаться другое изображение, пока оно все еще загружается, поэтому я установил фиктивное изображение вместо старой фотографии.

Это не самая лучшая реализация, но она предназначена для того, чтобы показать вам, что реализовать ее самостоятельно и сделать это правильно может быть очень сложно.

Прочитайте документацию Picasso и посмотрите, как это можно реализовать в вашем коде (это просто, это всего одна строка.)

Комментарии:

1. Спасибо за библиотеку и ваш ответ. Похоже, это решит проблемы, просто надеюсь, что так оно и будет. Я это реализую и дам вам знать.

2. эй, я попробовал picasso, загрузка работает нормально, но все же изображения сначала отображаются в нужном месте, но когда я прокручиваю после этого, изображения отображаются в неправильных элементах listview. Пожалуйста, помогите мне с этой проблемой.

Ответ №2:

Проблема в listview, который постоянно обновляет его.

Итак, весь ваш код в порядке, но просто установите изображение по умолчанию в holder.img вместо того, чтобы делать его нулевым holder.img.setImageBitmap (null);

И, возможно, также в асинхронном режиме, вам нужно установить default_image во время загрузки вашего изображения.

Ответ №3:

Если вы хотите отображать изображения на лету, я думаю, вам следует использовать SurfaceView. Это намного быстрее и имеет более высокую частоту обновления. Я создал приложение для потокового видео, в котором я пытался отобразить каждый видеокадр в ImageView, но это не удалось. Но когда я опробовал SurfaceView, все получилось отлично.