Android ListView Universal Image Loader изменяет изображения на прокрутке

У меня проблема, которая уже несколько недель огорчает меня. Я забыл об этом некоторое время, когда я обновлялся до нового SDK для Facebook, но теперь он снова преследует мои мечты.

Я делаю в основном читатель фида Facebook. Он получает данные JSON из вызова API и использует это для заполнения ListView. Каждый раз, когда пользовательский адаптер вызывает метод getView (), он проверяет, какой тип «статуса» он есть. Если это статус «фото», представление будет иметь два изображения (изображение профиля и изображение обновления статуса). Я использую универсальный загрузчик изображений nostra13 для загрузки обоих изображений после раздувания ImageViews с использованием класса держателей, чтобы помочь переработать виды. Вот где я думаю, что моя проблема существует.

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

1.) Все загружают одно и то же изображение (раньше у меня не было этой проблемы, но я дал это себе, пытаясь исправить остальные).

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

3.) Если изображения загружаются правильно и не все показывают одно и то же изображение, изображения меняются при прокрутке вверх и вниз, в конечном итоге все становится одним и тем же изображением.

Я выложу свой код getView () (извините, что он длинный).

@Override public View getView(final int position, View convertView, ViewGroup parent) { final ViewHolder holder; try { jsonObject = getItem(position); jsonFrom = jsonObject.getJSONObject("from"); postType = jsonObject.getString("type"); posterName = jsonFrom.getString("name"); posterID = jsonFrom.getString("id"); posterPhoto = "http://graph.facebook.com/" + posterID + "/picture?type=square"; if (jsonObject.has("message")) { posterMessage = jsonObject.getString("message"); } else { posterMessage = jsonObject.getString("story"); } } catch (JSONException e) { e.printStackTrace(); } if (postType.equals("status")) { if (convertView == null) { LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.status_post_holder,null); holder = new ViewHolder(); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.posterName = (TextView) convertView.findViewById(R.id.posterName); holder.posterMessage = (TextView) convertView.findViewById(R.id.posterMessage); holder.posterProfilePhoto = (ImageView) convertView.findViewById(R.id.posterProfilePic); if (jsonObject != null) { holder.posterName.setText(posterName); if (posterMessage != null) { holder.posterMessage.setText(posterMessage); } else { holder.posterMessage.setText("No message for this post."); } profileImageLoader.displayImage(posterPhoto, holder.posterProfilePhoto); } } else if (postType.equals("photo")) { if (convertView == null) { try { posterImageURL = jsonObject.getString("picture"); } catch (JSONException e) { e.printStackTrace(); } LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.photo_post_holder, null); holder = new ViewHolder(); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.posterName = (TextView) convertView.findViewById(R.id.posterName); holder.posterMessage = (TextView) convertView.findViewById(R.id.posterMessage); holder.posterProfilePhoto = (ImageView) convertView.findViewById(R.id.posterProfilePic); holder.posterImage = (ImageView) convertView.findViewById(R.id.posterImage); if (jsonObject != null) { holder.posterName.setText(posterName); if (posterPhoto != null) { profileImageLoader.displayImage(posterPhoto,holder.posterProfilePhoto); } if (posterImageURL != null) { pictureImageLoader.displayImage(posterImageURL,holder.posterImage); } if (posterMessage != null) { holder.posterMessage.setText(posterMessage); } else { holder.posterMessage.setText("No message for this post."); } } } else if (postType.equals("link")) { if (convertView == null) { LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.status_post_holder,null); holder = new ViewHolder(); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.posterName = (TextView) convertView.findViewById(R.id.posterName); holder.posterMessage = (TextView) convertView.findViewById(R.id.posterMessage); holder.posterProfilePhoto = (ImageView) convertView.findViewById(R.id.posterProfilePic); if (jsonObject != null) { holder.posterName.setText(posterName); if (posterMessage != null) { holder.posterMessage.setText(posterMessage); } else { holder.posterMessage.setText("No message for this post."); } profileImageLoader.displayImage(posterPhoto,holder.posterProfilePhoto); } } else { if (convertView == null) { LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.status_post_holder,null); holder = new ViewHolder(); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.posterName = (TextView) convertView.findViewById(R.id.posterName); holder.posterMessage = (TextView) convertView.findViewById(R.id.posterMessage); holder.posterProfilePhoto = (ImageView) convertView.findViewById(R.id.posterProfilePic); if (jsonObject != null) { holder.posterName.setText(posterName); if (posterMessage != null) { holder.posterMessage.setText(postType); } else { holder.posterMessage.setText("No message for this post."); } profileImageLoader.displayImage(posterPhoto,holder.posterProfilePhoto); } } return convertView; } 

Я уверен, что это имеет какое-то отношение к просмотрам приложений Android и их эффективности, но я не могу понять, где я делаю ошибку. Также странно, что проблема существует только для одного изображения. Любая помощь будет горячей. Благодарю.

ОБНОВЛЕНИЕ: Мы обнаружили, что это была ошибка с моим анализом JSON. Вы должны использовать setTag (), чтобы сохранить изображение, специфичное для этой позиции. Адаптер пытался установить тег null для представления, который вызвал NPE.

UPDATE AGAIN: После копания еще немного, похоже, что сам ImageView дает нулевое значение, как будто он не находит правильный макет. Я использовал два разных xml-макета для разных типов сообщений. Итак, теперь похоже, что лучшим решением было бы использовать один и тот же макет и просто условно раздувать разные элементы в каждом представлении в зависимости от типа состояния.

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

См. Ниже класс адаптера и попробуйте интегрировать его в свой случай. Который поможет вам.

  private class OrderAdapter extends ArrayAdapter<User> { private ArrayList<User> items; Activity a; public ImageLoader imageLoader; public OrderAdapter(Context context, int textViewResourceId,ArrayList<User> items) { super(context, textViewResourceId, items); this.items = items; // extra /*if (Utility.model == null) { Utility.model = new FriendsGetProfilePics(); } Utility.model.setListener(this);*/ } /*@Override public boolean isEmpty() { // TODO Auto-generated method stub super.isEmpty(); return false; }*/ @Override public View getView(final int position, View convertView,ViewGroup parent) { ViewHolder holder; View v = convertView; if (v == null) { LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.add_buddies_row_new, null); holder = new ViewHolder(); imageLoader = new ImageLoader(NotificationsActivity.this); //-------------- //--------------------------------------------------------------------- // for head to head holder.userName = (TextView) v.findViewById(R.id.txtName); holder.userPic = (ImageView) v.findViewById(R.id.imgUserPic); holder.userCity = (TextView) v.findViewById(R.id.txtCity); holder.userState = (TextView) v.findViewById(R.id.txtstate); holder.userCountry = (TextView) v.findViewById(R.id.txtContry); //--------------------------------------------------------------------- v.setTag(holder); }else{ holder=(ViewHolder)v.getTag(); } final User o = items.get(position); holder = (ViewHolder) v.getTag(); if (o != null) { holder.userName.setText(o.getUserName()); holder.userCity.setText(o.getUserCity()+", "); holder.userState.setText(o.getUserState()+", "); holder.userCountry.setText(o.getUserCountry()); System.out.println("PIC: "+o.getUserPic()); holder.userPic.setTag(o.getUserPic()); imageLoader.DisplayImage(o.getUserPic(), a, holder.userPic); } return v; } } class ViewHolder { TextView userName ; TextView userCity; TextView userState; TextView userCountry; ImageView userPic ; } 

Прокомментируйте меня для любой мысли.

Примечание: ВЫ ДОЛЖНЫ СДЕЛАТЬ НЕКОТОРЫЕ ИЗМЕНЕНИЯ В ВЫШЕМ КОДЕ КАК НА ВАШЕ ТРЕБОВАНИЕ.

Если ваша проблема не решится с этим, то дайте мне знать.

Это также может случиться, если вы получаете нулевые данные, поэтому, пожалуйста, подтвердите получение данных.

Я знаю, что прошло некоторое время с тех пор, как была создана тема, но мое решение для NPE @Wenger произошло из-за того, что я использовал findViewById в элементе View, называемом v вместо ViewHolder:

 holder.userName = (TextView) v.findViewById(R.id.txtName); 

Рабочая ссылка:

 holder.userName = (TextView) convertView.findViewById(R.id.txtName); 

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

Я проверял свой url, прежде чем я назову универсальное изображение загрузчика загрузчика, и если url был null, я не загружаю изображение, просто устанавливаю изображение. В прокрутке Listview мои изображения в списке были смешаны.

Затем я попытался не проверять URL-адрес, если его значение равно null, и просто установить URL-адрес, недоступный для универсального изображения. Это устранило мою проблему. Я не знаю, является ли это решением для решения этой проблемы, но вы можете попробовать.

Прежде всего рассмотрим использование типов просмотров – getViewTypeCount() & getItemViewType(int position)ListView будет уважать ваши разные взгляды – больше информации: как работает переработка ListView .

Кроме того, просто не getView() json в getView() – делайте это там, где вы его получаете.

Также (как указано выше) вы должны запустить ImageLoader только один раз – идеальное место для этого – это onCreate () вашего приложения. Затем вы вызываете его – ImageLoader.getInstance().loadSmth() ;

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

  final int viewType = getItemViewType(position); final int layoutResId; switch (viewType) { case 0: layoutResId = R.layout.layout_1; break; case 1: layoutResId = R.layout.layout_2; break; default: layoutResId = R.layout.layout_3; } final View view = mInflater.inflate(layoutResId, group, false); 

Есть несколько исправлений, которые вы можете сделать

Держатель вашего вида почти бесполезен. Вы должны использовать его, как следует

 ViewHolder viewHolder; if (view == null) { viewHolder = new ViewHolder(); viewHolder.image = (ImageView) view.findViewById(R.id.capsule_media_list_item_thumbnail_1); view.setTag(viewHolder); }else{ viewHolder = view.getTag(viewHolder); } 

Вы должны объявить экземпляр ImageLoader и DisplayImageOptions только один раз. Возможно, в конструкторе.

 ImageLoader imageLoader = ImageLoader.getInstance(); DisplayImageOptions options = new DisplayImageOptions.Builder().cacheInMemory(true) .cacheOnDisc(true).resetViewBeforeLoading(true) .showImageForEmptyUri(fallbackImage) .showImageOnFail(fallbackImage) .showImageOnLoading(fallbackImage).build(); 
Intereting Posts
Как проверить ListActivity, издеваясь над его contentProvider и тем самым изолировать тест от базы данных? Невозможно получить значение JNIEnv * в произвольном контексте Не удается разрешить символ для фрагментов Как использовать дополнительные * .so библиотеки на Android Studio и NDK Как получить имя хоста или имя устройства устройств, подключенных к моей локальной сети через Android? Android: java.land.NoSuchFieldError после обновления до SDK 23 Путь APK не указан для модуля «Пример-пример» EditText – Как установить текст по умолчанию в android edittext Могу ли я напрямую проверить транзакционную информацию о биллинге в приложении с сервером Android Market? Ошибка Snackbar и FloatingActionButton ImageView не отображается в титане андроида Предоставляются ли общие предпочтения пользователям Стилизация спиннера, апплета, материала Android AbsListView $ RecycleBin.addScrapView (AbsListView.java:6588) Какова практичность использования PhoneGap?