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

Viewed 1092

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:

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?

2 Answers
Related