0

I've tried to build my app on top of a opensource project. The basic function is to use GridView to show a couple of images. The following is the code snippet. The comment line is the original code. In the original code, Images.imageThumbUrls is a string array of urls and the size(Images.imageThumbUrls.length) is 99. I'd like to replace the original urls with my own version and I did. But there is an error. Please see the log.

According to the log, it seems that the limit for getView is 99(the original code). Aside from changing getCount, is there anything else I need to do?

In createView method:

        mGridView.getViewTreeObserver().addOnGlobalLayoutListener(
            new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    if (mAdapter.getNumColumns() == 0) {
                        final int numColumns = (int) Math.floor(
                                mGridView.getWidth() / (mImageThumbSize + mImageThumbSpacing));
                        if (numColumns > 0) {
                            final int columnWidth =
                                    (mGridView.getWidth() / numColumns) - mImageThumbSpacing;
                            mAdapter.setNumColumns(numColumns);
                            mAdapter.setItemHeight(columnWidth);
                            if (BuildConfig.DEBUG) {
                                Log.d(TAG, "onCreateView - numColumns set to " + numColumns);
                            }
                        }
                    }
                }
            });

ImageAdapter class:

private class ImageAdapter extends BaseAdapter {        
public int getCount() {
        //return Images.imageThumbUrls.length + mNumColumns;
        return DataStore.photosInfoOfTag.total + mNumColumns;
}
    @Override
    public View getView(int position, View convertView, ViewGroup container) {
        // First check if this is the top row
        if (position < mNumColumns) {
            if (convertView == null) {
                convertView = new View(mContext);
            }
            // Set empty view with height of ActionBar
            convertView.setLayoutParams(new AbsListView.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, mActionBarHeight));
            return convertView;
        }

        // Now handle the main ImageView thumbnails
        ImageView imageView;
        if (convertView == null) { // if it's not recycled, instantiate and initialize
            imageView = new RecyclingImageView(mContext);
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            imageView.setLayoutParams(mImageViewLayoutParams);
        } else { // Otherwise re-use the converted view
            imageView = (ImageView) convertView;
        }

        // Check the height matches our calculated column width
        if (imageView.getLayoutParams().height != mItemHeight) {
            imageView.setLayoutParams(mImageViewLayoutParams);
        }

        // Finally load the image asynchronously into the ImageView, this also takes care of
        // setting a placeholder image while the background thread runs
        Photo photo = DataStore.photosInfoOfTag.photo.get(position - mNumColumns);
        String photoUrl = DataStore.imageUrlPart1 + Integer.toString(photo.getFarm()) +
                          DataStore.imageUrlPart2 + photo.getServer() + "/" + 
                          photo.getId() + "_" + photo.getSecret() +
                          DataStore.imageUrlPart3;
        mImageFetcher.loadImage(photoUrl, imageView);
        //mImageFetcher.loadImage(Images.imageThumbUrls[position - mNumColumns], imageView);
        return imageView;
    }

    public void setItemHeight(int height) {
        if (height == mItemHeight) {
            return;
        }
        mItemHeight = height;
        mImageViewLayoutParams =
                new GridView.LayoutParams(LayoutParams.MATCH_PARENT, mItemHeight);
        mImageFetcher.setImageSize(height);
        notifyDataSetChanged();
    }

    public void setNumColumns(int numColumns) {
        mNumColumns = numColumns;
    }
}

05-06 01:04:39.736: E/AndroidRuntime(16356): FATAL EXCEPTION: main

05-06 01:04:39.736: E/AndroidRuntime(16356):
java.lang.IndexOutOfBoundsException: Invalid index 100, size is 100

05-06 01:04:39.736: E/AndroidRuntime(16356): at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)

05-06 01:04:39.736: E/AndroidRuntime(16356): at java.util.ArrayList.get(ArrayList.java:304)

05-06 01:04:39.736: E/AndroidRuntime(16356): at com.example.android.bitmapfun.ui.ImageGridFragment$ImageAdapter.getView(ImageGridFragment.java:292)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.widget.AbsListView.obtainView(AbsListView.java:2143)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.widget.GridView.makeAndAddView(GridView.java:1341)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.widget.GridView.makeRow(GridView.java:341)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.widget.GridView.fillDown(GridView.java:283)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.widget.GridView.fillGap(GridView.java:243)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.widget.AbsListView.trackMotionScroll(AbsListView.java:4930)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:4087)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.view.Choreographer.doCallbacks(Choreographer.java:562)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.view.Choreographer.doFrame(Choreographer.java:531)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.os.Handler.handleCallback(Handler.java:725)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.os.Handler.dispatchMessage(Handler.java:92)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.os.Looper.loop(Looper.java:137)

05-06 01:04:39.736: E/AndroidRuntime(16356): at android.app.ActivityThread.main(ActivityThread.java:5041)

05-06 01:04:39.736: E/AndroidRuntime(16356): at java.lang.reflect.Method.invokeNative(Native Method)

05-06 01:04:39.736: E/AndroidRuntime(16356): at java.lang.reflect.Method.invoke(Method.java:511)

05-06 01:04:39.736: E/AndroidRuntime(16356): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)

05-06 01:04:39.736: E/AndroidRuntime(16356): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)

05-06 01:04:39.736: E/AndroidRuntime(16356): at dalvik.system.NativeStart.main(Native Method)

Fihop
  • 3,127
  • 9
  • 42
  • 65
  • Is that the full code in the `getView()` method? If not please post it, otherwise I don't see how your code manages to pass the negative index list retrieval(as position starts from 0 and assuming mNumColumns is not 0). – user May 06 '13 at 16:35
  • What you posted is not clear. `Images.imageThumbUrls.length` represents `DataStore.photosInfoOfTag.total` in your code? In this case if `Images.imageThumbUrls.length` is 99 how does the exception states you have a list of 100 elements? – user May 06 '13 at 17:56
  • @Luksprog, `Images.imageThumbUrls.length` is 99. I changed it to `DataStore.photosInfoOfTag.total`, which is about 10000. – Fihop May 06 '13 at 18:02
  • @Luksprog,Thanks so much for your patient. I made a mistake. The length of DataStore.photosInfoOfTag.total is 100. Sorry for wasting your time. – Fihop May 06 '13 at 18:21

1 Answers1

1

Be carefull, when returning a value on getCount() greater than the number of items at the Adapter (usually to fill only cells) you need to check if the current bounds is never bypassed, and if so return a empty view (or one with some background).

Your code:

public int getCount() {
        //return Images.imageThumbUrls.length + mNumColumns;
        return DataStore.photosInfoOfTag.total + mNumColumns;
}

Should only return DataStore.photosInfoOfTag.total

Also, do not use static things like this, you should use a List instead as the data of the adapter.

Marcos Vasconcelos
  • 18,136
  • 30
  • 106
  • 167
  • I'm confused this problem. The reason to return `DataStore.photosInfoOfTag.total + mNumColumns;` is because "This is fairly standard except the number of columns in the GridView is used to create a fake top row of empty views as we use a transparent ActionBar and don't want the real top row of images to start off covered by it." – Fihop May 06 '13 at 18:09
  • @Macros, Thanks so much for your patient. I made a mistake. The length of `DataStore.photosInfoOfTag.total` is 100. Sorry for wasting your time. – Fihop May 06 '13 at 18:21
  • Nope, i usually use counts greater than the data to fill the remaining space of a row in a GridView, but you need to return a empty view for that cases. – Marcos Vasconcelos May 06 '13 at 18:50