Android ListView универсальный загрузчик изображений изменяет изображения при прокрутке


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

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

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

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 и эффективностью, но я не могу понять, где я делаю ошибка. Также странно, что проблема существует только для одного вида изображения. Любая помощь будет горячей. Спасибо.

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

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

5 7

5 ответов:

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

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

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

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

Примечание: Вы должны сделать некоторые изменения в вышеуказанном коде согласно вашему требованию.

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

Он может также произошло, если вы получаете нулевые данные, поэтому, пожалуйста, подтвердите получение данных.

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

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

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

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

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

Я проверял свой url перед вызовом universal loader display image и если url был равен нулю, я не загружал изображение, просто устанавливал ImageView background drawable my no image drawable. По ListView прокрутки мой ListView с изображениями были смешанные.

Затем я попытался не проверять url, если его значение равно null, а просто установить нет url drawable для universal image loader display image options. Это решило мою проблему. Я не знаю, что это такое. общее решение для этой проблемы, но вы можете попробовать его.

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

Кроме того, просто не разбирайте 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();