2
votes

I have GridView in which images are being downloaded from server, I have used lazy loading methodology for asynchronously adding images to grid.

I can see getView method being called many times and inconsistently for positions of grid view till images are being downloaded for position.

Now, when i scroll gridview, images which are already downloaded for position are now getting replaced by other images.

But after all images are downloaded for position, it works fine.

I know and have read previous post for getView inconsistent call, but still not able to resolve issue.

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

Where: imageLoader.DisplayImage(onDemandItem.getPosterUrl(), viewHolder.image, onDemandItem.getGenrePlaceHolder()); is image asynchronous download method

3
Post your getView method, we can help you more when we have more information. A number of things might be wrong.HandlerExploit
This sounds like it may be caused by recycled views and asynchronous callbacks. Need your code to verifySpidy
@HandlerExploit Edited my question, with getView method attached alongZoombie
@Spidy : Yes i think same as you, pls find attached getView code in questionZoombie

3 Answers

1
votes

I had the same problem before. Here is my solution in pseudocode (I use monodroid, so not sure how it works in java, but algorithm shoud be clear)

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

So, every time Adapter asks me for data, I mark a view with a random revision number. When I use lazy load, I pass this number into loader, which keeps it during the loading process. When loading is completed, I compare current view revision and revision, returned by loader. If they are equals, it's ok and I set the image. If not, this means that during loading period user scrolled my ListView (GridView) and current View is ANOTHER view than one, who requested the image into view. If I'll set image into it, i'll replace image by depracated one, so I simply ignore this case.

0
votes

Try using setTag method along with imageview, my solution works like this, in getView method of adapter, setTag to imageview being loaded.

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

and in imageLoader class, before attaching bitmap loaded to imageview, check whether imageview's getTag and url passed to loader class.

0
votes

I solved this issue using two hashmaps. As the view renders a map is made containing the items and also the corresponding convertView objects. You need to ensure a unique id is available on the incoming OnDemandItem item which can be used to key the hashmaps.

So re-working your code:

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

}