0

I am using SectionIndexer for an ArrayAdapter and have fast scrolling enabled. Most lists work fine, but a couple crash at the same point and show the same type of log.

(Please note: The ListView is based on data inputted from a MySQL table. The list has about 2000 items. But the SQL in the list has a "where clause" where only 100-200 may show at a time. It appears the thumb scroller naturally scrolls the size of the 2000 items, and is not corresponding to this "where clause". I don't believe this is a PHP/MySQL issue but in my Android/Java.)

Here is log:

08-27 07:26:33.360: E/AndroidRuntime(9145): FATAL EXCEPTION: main
08-27 07:26:33.360: E/AndroidRuntime(9145): java.lang.ArrayIndexOutOfBoundsException: length=21; index=21-
08-27 07:26:33.360: E/AndroidRuntime(9145):     at com.---.---.ItemAdapter.getPositionForSection(ItemAdapter.java:57)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at android.widget.FastScroller.getThumbPositionForListPosition(FastScroller.java:650)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at android.widget.FastScroller.onScroll(FastScroller.java:458)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at android.widget.AbsListView.invokeOnItemScrollListener(AbsListView.java:1325)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5067)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:4205)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at android.view.Choreographer.doCallbacks(Choreographer.java:555)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at android.view.Choreographer.doFrame(Choreographer.java:524)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at android.os.Handler.handleCallback(Handler.java:615)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at android.os.Handler.dispatchMessage(Handler.java:92)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at android.os.Looper.loop(Looper.java:137)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at android.app.ActivityThread.main(ActivityThread.java:4928)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at java.lang.reflect.Method.invokeNative(Native Method)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at java.lang.reflect.Method.invoke(Method.java:511)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:558)
08-27 07:26:33.360: E/AndroidRuntime(9145):     at dalvik.system.NativeStart.main(Native Method)

Here is code by Line 57:

public int getPositionForSection(int section) {
    return alphaIndexer.get(sections[section]);
}

Also, here is more code in the adapter:

alphaIndexer = new HashMap<String, Integer>();
int size = objects.length;

for (int i = 0; i < size; i++) {

    ItemObject it = objects[i];
    String name = it.name;
    String s = name.substring(0, 1);
    s = s.toUpperCase();

    if (!alphaIndexer.containsKey(s)) {
        alphaIndexer.put(s, i);
    }
}

Set<String> sectionLetters = alphaIndexer.keySet();
ArrayList<String> sectionList = new ArrayList<String>(sectionLetters);
Collections.sort(sectionList);
sections = new String[sectionList.size()];

// sectionList.toArray(sections);

for (int i = 0; i < sectionList.size(); i++)
    sections[i] = sectionList.get(i);


public int getSectionForPosition(int position)

{
    int closestIndex = 0;
    int latestDelta = Integer.MAX_VALUE;

    for(int i=0; i < sections.length; i++) {

        Log.d("Sections Length: ", String.valueOf(sections.length));

        int current = alphaIndexer.get(sections[i]);
        if(current == position) {
            //If position matches an index, return it immediately
            return i;
        } else if(current < position) {
            //Check if this is closer than the last index we inspected
            int delta = position - current;
            if(delta < latestDelta) {
                closestIndex = i;
                latestDelta = delta;
            }
        }
    }

    return closestIndex;
}

public Object[] getSections() {
    return sections;
}
TheLettuceMaster
  • 15,594
  • 48
  • 153
  • 259
  • Can you provide more details about when this happens(like scrolling at the end of the list, middle, after a data reset etc)? – user Aug 27 '12 at 15:19
  • There is no pattern; sometimes middle, sometimes end. I did confirm via Logging out the Section ArrayList that the expected variables are being entered; the only thing I can think of there is something wrong with the data maybe, not the code? I am going to be checking my table items next. – TheLettuceMaster Aug 27 '12 at 15:36
  • @Luksprog update: The `MySQL` tables did not have hidden data or anything out of ordinary. There are 2 lists of 20 that crash. They are all coming from same table with different `where` clause. 1 crashes almost at bottom, the other around 50% down list. It crashes when scrolling normally, not using thumbscroller. One list has 7 items in `SectionIndexer`. Crashes when it hits the 8th. I printed out the `ArrayList` each time the scrolling gesture is used (via `Log`); it shows only 7 in the `ArrayList` up until the crash that says there are 8 items. I can't get it to print out that 8th item. – TheLettuceMaster Aug 27 '12 at 17:47
  • 1
    Can you test this version of `getSectionForPosition` : `public int getSectionForPosition(int position) { for(int i = sections.length; i >= 0 ; i--) { int currentSection = alphaIndexer.get(sections[i]); if (position >= currentSection) { return i; } } }` – user Aug 27 '12 at 18:25
  • @Luksprog Well, Eclipse says that it needs a return statement? by default it says "return position" which I believe is wrong. – TheLettuceMaster Aug 28 '12 at 00:43
  • @Luksprog One more note, I just noticed the Array Exception is actually coming from the getPositionForSection method. – TheLettuceMaster Aug 28 '12 at 01:06
  • Just an update, I figured out the issue and should post tomorrow. We were looking in the wrong area. It had to do with the code when it put the ArrayList sections into the Array. Thanks for your help! – TheLettuceMaster Aug 28 '12 at 03:23

2 Answers2

1

Her is my final code that worked:

    int size = objects.length;


        for (int i = 0; i < size; i++) {

            ItemObject it = objects[i];
            String name = it.name;
            String s = name.substring(0, 1);
            s = s.toUpperCase();

            if (!alphaIndexer.containsKey(s)) {

                alphaIndexer.put(s, i);
            }
        }

        Set<String> sectionLetters = alphaIndexer.keySet();
        ArrayList<String> sectionList = new ArrayList<String>(sectionLetters);
        Collections.sort(sectionList);
        sections = new String[sectionList.size()];
        for (int i = 0; i < sectionList.size(); i++) {
            sections[i] = sectionList.get(i);
        }

    }


public int getPositionForSection(int section) {

        int maxSize = sections.length - 1;

        if (section > maxSize) {
            return 0;
        } else {

            return alphaIndexer.get(sections[section]);
        }
    }

    public int getSectionForPosition(int position)

    {
        int closestIndex = 0;
        int latestDelta = Integer.MAX_VALUE;

        for (int i = 0; i < sections.length; i++) {

            int current = alphaIndexer.get(sections[i]);
            if (current == position) {
                // If position matches an index, return it immediately
                return i;
            } else if (current < position) {
                // Check if this is closer than the last index we inspected
                int delta = position - current;
                if (delta < latestDelta) {
                    closestIndex = i;
                    latestDelta = delta;
                }
            }
        }

        return closestIndex;
    }
TheLettuceMaster
  • 15,594
  • 48
  • 153
  • 259
0

Please see https://code.google.com/p/android/issues/detail?id=33293

They suggest to check the bounds of the array:

@Override
public int getPositionForSection(int section) {
    if (section > sections.length - 1) {
        return mItems.size() - 1;
    } else {
        return alphaIndexer.get(sections[section]);
    }
}

The documentation for both methods getPositionForSection and getSectionForPosition says:

If the section's starting position is outside of the adapter bounds, the position must be clipped to fall within the size of the adapter.

petrsyn
  • 5,054
  • 3
  • 45
  • 48