Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is changing where layout parameters are set solving my "OnClickListener not working for first item in GridView" issue?

I'm using a GridView to show some images and I had a problem, as the onClickListener wasn't working for the first image. I found some other questions here at SO with the same problem, but I don't like their "correct answers", as most of them take the same approach of:

  • OnClickListener not working for first item in GridView inside ViewPager

Basically, instantiating the view every time getview is called. This is awful for performance and they will probably face out-of-memory issues in many devices.

In my case, I display in the GridView the images located inside a sub-folder in the assets folder.

My original code with the "first item" issue (actually, my original code implemented the viewholder pattern, but this one is a bit simpler and faces the same issue):

    @Override
public View getView(int position, View convertView, ViewGroup parent) {
    ImageView imageView;

    if (convertView == null) {
        imageView = new ImageView(_activity);

    } else {
        imageView = (ImageView) convertView;
    }

    // get screen dimensions
    AssetManager assetManager = _activity.getAssets();
    InputStream assetIn = null;
    try {
        assetIn = assetManager.open(_assets_subdir + File.separator + _filePaths.get(position));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    Bitmap image = BitmapFactory.decodeStream(assetIn);
    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    imageView.setLayoutParams(new GridView.LayoutParams(imageWidth, imageWidth));
    imageView.setImageBitmap(image);

    // image view click listener
    imageView.setOnClickListener(new OnImageClickListener(position));

    return imageView;

}

My final code solving the issue:

    @Override
public View getView(int position, View convertView, ViewGroup parent) {
    ImageView imageView;

    if (convertView == null) {
        imageView = new ImageView(_activity);
        imageView.setLayoutParams(new GridView.LayoutParams(imageWidth, imageWidth));

    } else {
        imageView = (ImageView) convertView;
    }

    // get screen dimensions
    AssetManager assetManager = _activity.getAssets();
    InputStream assetIn = null;
    try {
        assetIn = assetManager.open(_assets_subdir + File.separator + _filePaths.get(position));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    Bitmap image = BitmapFactory.decodeStream(assetIn);
    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    imageView.setImageBitmap(image);

    // image view click listener
    imageView.setOnClickListener(new OnImageClickListener(position));

    return imageView;

}

The issue was solved moving the code imageView.setLayoutParams(new GridView.LayoutParams(imageWidth, imageWidth));.

But why? I'm not sure.

I read somewhere (in SO) that it could be happening because of trying to access a view that has not been inflated yet, and the user recommended using getViewTreeObserver(), but I tried that approach and couldn't fix the problem.

So, I decided to trial-and-error the code to see where to bottleneck could be and found the given solution.

Anyone knows why is this solving the problem?

like image 583
Alejandro Colorado Avatar asked Nov 11 '22 17:11

Alejandro Colorado


1 Answers

GridView extends from AbsListView -> GridView.LayoutParams is actually AbsListView.LayoutParams, which includes some state data about the view's type and whether or not it is recycled.

By initialising a new set of layout params each time getView is called (and not just when the view is created anew), you were losing this state data.

I'm not (currently) sure why it was only causing an issue for the first item in the grid.

like image 95
FunkTheMonk Avatar answered Nov 15 '22 11:11

FunkTheMonk