androidgridviewonitemclicklistenerandroid-adapterview

First item in gridview does not change in the AdapterView.OnItemClickListener


I have a grid view of images. When click on an image I set a little check mark drawable to mark it as selected, and when another item is clicked I go through all items and remove the check mark.

The problem is my first item in the grid view does not get updated after it is checked. It simply does not do anything after it is checked. All other items work as expected - they get checked when clicked and unchecked when another item is clicked. Only the first item stays checked when it is clicked and does not change when other items are clicked.

Below is the onItemClickListener code. Any ideas?

for (int i = 0; i < shapeIds.length; i++) {
    ImageView imageView = (ImageView) adapterView.getItemAtPosition(i);
    imageView.setImageDrawable(null); // does not work on item 0
}

Drawable check = VectorDrawableCompat.create(getResources(), R.drawable.check_circle, null);
((ImageView) view).setImageDrawable(check);

EDIT: Adding more code to help understand the issue. Here is my adapter code:

public class ImageAdapter extends BaseAdapter {

    private Context context;
    private ImageView imageView;
    private int[] itemIds;
    private ImageView[] views;

    ImageAdapter(Context c, int[] itemIds) {
        context = c;
        this.itemIds = itemIds;
        views = new ImageView[itemIds.length];
    }

    @Override
    public int getCount() {
        return itemIds.length;
    }

    @Override
    public Object getItem(int position) {
        return views[position];
    }

    @Override
    public long getItemId(int position) {
        return itemIds[position];
    }

    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup) {

        imageView = new ImageView(context);
        Drawable mainDrawable = VectorDrawableCompat.create(getResources(), itemIds[position], null);
        imageView.setBackground(mainDrawable);
        views[position] = imageView;
        return imageView;
    }
}

Solution

  • When logging from getView(), you may have noticed that this method seems to get called at least twice for position=0.

    You are keeping an array of ImageViews which is populated from getView(), but at least for position=0 you can't be sure that the ImageView you create there will in fact be added to the GridView.

    What can you do to solve your issue? One option is to keep itemIds as the Adapter's data and not try to manage the ImageViews yourself. Instead, the Adapter could keep track of the checked position like this:

    public class ImageAdapter extends BaseAdapter {
    
        private Context context;
        private ImageView imageView;
        private int[] itemIds;
        private int checkedPosition = -1;
        private Drawable check;
    
        ImageAdapter(Context c, int[] itemIds) {
            context = c;
            check = VectorDrawableCompat.create(context.getResources(), R.drawable.ic_check_circle, null);
            this.itemIds = itemIds;
        }
    
        public void setCheckedPosition(int checkedPosition){
            this.checkedPosition = checkedPosition;
        }
    
        @Override
        public int getCount() {
            return itemIds.length;
        }
    
        @Override
        public Object getItem(int position) {
            return itemIds[position];
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup viewGroup) {
    
            imageView = new ImageView(context);
            Drawable mainDrawable = VectorDrawableCompat.create(getResources(), itemIds[position], null);
            imageView.setBackground(mainDrawable);
            if(checkedPosition == position){
    
                imageView.setImageDrawable(check);
            }
            else{
                imageView.setImageDrawable(null);
            }
            return imageView;
        }
    }
    

    BTW it may be a good idea to implement the ViewHolder pattern, but I'm skipping this here to stay as close as possible to your code.

    Your OnItemClickListener would look as follows:

    final ImageAdapter adapter = new ImageAdapter(this, shapeIds);
    gridView.setAdapter(adapter);
    
    gridView.setOnItemClickListener(new AdapterView.OnItemClickListener()
    {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id)
        {
            adapter.setCheckedPosition(position);
            adapter.notifyDataSetChanged();
        }
    });