getView ArrayAdapter несовместим с загрузкой изображения

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

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

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

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

Я знаю и прочитал предыдущий пост о несогласованном вызове getView, но до сих пор не могу решить проблему.

`@Override public View getView(final int position, View convertView, final ViewGroup viewGroup) { ViewHolder viewHolder;

    if (convertView == null) {
        convertView = layoutInflater.inflate(R.layout.ondemand_grid_item,
                null);

        viewHolder = new ViewHolder();
        viewHolder.title = ((TextView) convertView
                .findViewById(R.id.ondemand_grid_item_title));
        viewHolder.image = ((ImageView) convertView
                .findViewById(R.id.ondemand_grid_item_image));
        viewHolder.iconImage = ((ImageView) convertView
                .findViewById(R.id.on_demand_trailer_icon));
        viewHolder.showSelectedImage = (ImageView) convertView.findViewById(R.id.ondemand_grid_item_img);
        viewHolder.showSelectedImage.setVisibility(View.INVISIBLE);
        viewHolder.showSelectedImage.setSelected(true);
        viewHolder.seasonNumber = (TextView) convertView.findViewById(R.id.ondemand_grid_item_season);
        viewHolder.seasonNumber.setVisibility(View.INVISIBLE);

        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }

    final OnDemandItem onDemandItem = getItem(position);
    imageLoader.DisplayImage(onDemandItem.getPosterUrl(), viewHolder.image, onDemandItem.getGenrePlaceHolder());
    showHideTrailerIcon(viewHolder, onDemandItem);
    if (onDemandItem.getType() == AssetTypeEnum.SERIE) {
        if (onDemandItem.getSeasonNumber() != null && !"".equals(onDemandItem.getSeasonNumber())) {
            viewHolder.seasonNumber.setVisibility(View.VISIBLE);
            viewHolder.seasonNumber.setText("Seizoen " + onDemandItem.getSeasonNumber());
        }
    }
    viewHolder.title.setText(onDemandItem.getTitle());

    if (selectedOndemandItemId == onDemandItem.getId()) {
        convertView.findViewById(R.id.ondemand_grid_item_img).setVisibility(View.VISIBLE);
    } else {
        ImageView showSelectedImage = (ImageView) convertView.findViewById(R.id.ondemand_grid_item_img);
        if (showSelectedImage != null) {
            showSelectedImage.setVisibility(View.INVISIBLE);
        }
    }

    return convertView;
}`

Где: imageLoader.DisplayImage(onDemandItem.getPosterUrl(), viewHolder.image, onDemandItem.getGenrePlaceHolder()); это метод асинхронной загрузки изображений


person Zoombie    schedule 10.11.2011    source источник
comment
Опубликуйте свой метод getView, мы сможем помочь вам больше, когда у нас будет больше информации. Некоторые вещи могут быть неправильными.   -  person HandlerExploit    schedule 10.11.2011
comment
Похоже, это может быть вызвано переработанными представлениями и асинхронными обратными вызовами. Нужен ваш код для проверки   -  person Spidy    schedule 10.11.2011
comment
@HandlerExploit Отредактировал мой вопрос, добавив к нему метод getView   -  person Zoombie    schedule 11.11.2011
comment
@Spidy: Да, я думаю так же, как и вы, пожалуйста, найдите прикрепленный код getView, о котором идет речь.   -  person Zoombie    schedule 11.11.2011


Ответы (3)


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

public override View GetView (int position, View convertView, ViewGroup parent)
{
   View v = convertView;

   int rev = 0;
   lock(imageSync){
     if(v == null){
        LayoutInflater vi = (LayoutInflater)Context.GetSystemService (Context.LayoutInflaterService);
        v = vi.Inflate (_textViewResourceId, null);
     }

     rev = Math.Random();
     v.Tag = rev;
   }

   ImageView im = (ImageView)v.FindViewById (R.Id.image_view);
   if (im != null) {
      im.SetImageResource(R.Drawable.loading);
      ImageLoader loader = GetLoader();
      loader.OnImageLoadedListener=delegate (Drawable image, int backRev){
            lock(imageSync){
               if(((int)v.Tag) != backRev) return;
               else im.SetImage(image);
            }
      };
      loader.LoadImage(imageUrl, rev);
   }
}

Таким образом, каждый раз, когда Adapter запрашивает у меня данные, я помечаю представление случайным номером версии. Когда я использую ленивую загрузку, я передаю это число в загрузчик, который сохраняет его в процессе загрузки. Когда загрузка завершена, я сравниваю текущую ревизию представления и ревизию, возвращенную загрузчиком. Если они равны, все в порядке, и я устанавливаю изображение. Если нет, это означает, что в период загрузки пользователь прокручивал мой ListView (GridView), а текущий вид - ДРУГОЙ вид, чем тот, который запросил изображение для просмотра. Если я установлю в него изображение, я заменю изображение устаревшим, поэтому я просто игнорирую этот случай.

person PVoLan    schedule 10.11.2011
comment
Да .. я попробую, как вы упомянули - person Zoombie; 11.11.2011
comment
Я попытался использовать алгоритм, предложенный @PVolan, и он работает, устанавливая интерфейс при загрузке изображения и прикрепляя его обратно с помощью метода getView. Также столкнулся с проблемой ленивой загрузки класса загрузчика изображений, потому что он работает в другом потоке. но я решил это. - person Zoombie; 17.11.2011

Попробуйте использовать метод setTag вместе с изображением, мое решение работает так: в методе адаптера getView setTag загружается для просмотра изображения.

viewHolder.image.setTag(onDemandItem.getPosterUrl()) imageLoader.DisplayImage(onDemandItem.getPosterUrl(), viewHolder.image, onDemandItem.getGenrePlaceHolder());

и в классе imageLoader, прежде чем прикреплять растровое изображение, загруженное к изображению, проверьте, переданы ли getTag и URL-адрес изображения в класс загрузчика.

person Zoombie    schedule 17.11.2011
comment
Я нашел, что это лучше реализовать для асинхронной загрузки большого количества изображений и прикрепления растрового изображения изображения для правильного просмотра. - person Zoombie; 17.11.2011

Я решил эту проблему с помощью двух хэш-карт. По мере рендеринга представления создается карта, содержащая элементы, а также соответствующие объекты convertView. Вам необходимо убедиться, что для входящего элемента OnDemandItem доступен уникальный идентификатор, который можно использовать для ключей хэш-карт.

Итак, переработав ваш код:

//class variables
private HashMap<String, ViewHolder> mapDemandItems = new HashMap<>();
private HashMap<String, View> mapConvertView = new HashMap<>();

public View getView(int position, View convertView, ViewGroup parent) {
OnDemandItem onDemandItem = getItem(position);
viewHolder = mapDemandItems.get(onDemandItem.getId());

if (viewHolder == null) {
    viewHolder = new ViewHolder();
    convertView = layoutInflater.inflate(R.layout.ondemand_grid_item,
            null);

    //set viewHolder values

    mapDemandItems.put(onDemandItem.getId(), viewHolder);
    mapConvertView.put(onDemandItem.getId(), convertView);
} else {
    return mapConvertView.get(onDemandItem.getId());
}

...

return convertView;

}

person dblake78    schedule 03.08.2017