Android ListView array index out of bounds after filter

I think this is a question for experts.

I get calls to getView() with positon out of bounds from the ListView data list.
This happens when I use the Adapter filter. The filter publishResults() method populates the data with a filtered list which is smaller than the original list.
The error seems to occur when the new filtered list is shorter than the previous filtered list.
I changed the code of getView() to return a dummy convertView when out of bounds, just to see how many such calls are issued.

  • How can I add the new “Floating Action Button” between two widgets/layouts
  • Android: Spinner hint
  • Meaning of blinking red border in emulator
  • Gradle DSL method not found: 'runProguard'
  • Custom theme interferes with snackbar background color
  • Sharing data amongst activities and services
  • These are the relevant code and the log messages I logged:

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // No logs here to keep ListView performance good
            Log.d(TAG, "+ getView( position=" + position + ")");
            ViewHolder holder;
    
            if( position >= mData.size() ) {
                // This code allows to see how many bad calls I get
                Log.w(TAG, "position out of bounds!");
                convertView = mInflater.inflate(mLayout, parent, false);
                return convertView;
            }
    
            . . . // Normal getView code
    
            return convertView;
        }
    

    In the filter (code copied as is from ArrayAdapter source code)

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                Log.pe(TAG, "+ publishResults(constraint:" + constraint + ", results.count:" + results.count + ")");
                //noinspection unchecked
                mData = (ArrayList<String>) results.values;
                if (results.count > 0) {
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
                Log.px(TAG, "- publishResults()");
            }
    

    The log file shows that after a filter with 7 results, comes a fitler with 3 results, but getView keeps getting calls for 7 items (I marked with *** the out of bounds calls):

    02-26 05:31:55.986: D/ViewerActivity(22857): + onQueryTextChange(newText:log)
    02-26 05:31:55.986: D/ViewerActivity(22857): - onQueryTextChange()
    02-26 05:31:56.029: D/LogScreenAdapter(22857): + performFiltering(prefix:log)
    02-26 05:31:56.113: D/dalvikvm(22857): GC_CONCURRENT freed 378K, 5% free 13577K/14215K, paused 0ms+1ms
    02-26 05:31:56.153: D/LogScreenAdapter(22857): - performFiltering()
    02-26 05:31:56.153: D/LogScreenAdapter(22857): + publishResults(constraint:log, results.count:7)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): - publishResults()
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=0)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=0)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=0)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=1)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=2)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=3)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=4)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=5)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=6)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=0)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=1)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=2)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=3)
    02-26 05:31:56.167: D/LogScreenAdapter(22857): + getView( position=4)
    02-26 05:31:56.493: D/LogScreenAdapter(22857): + getView( position=5)
    02-26 05:31:56.503: D/LogScreenAdapter(22857): + getView( position=6)
    02-26 05:32:23.793: D/ViewerActivity(22857): + onQueryTextChange(newText:logs)
    02-26 05:32:23.793: D/ViewerActivity(22857): - onQueryTextChange()
    02-26 05:32:23.813: D/LogScreenAdapter(22857): + performFiltering(prefix:logs)
    02-26 05:32:23.854: D/dalvikvm(22857): GC_CONCURRENT freed 383K, 5% free 13577K/14215K, paused 0ms+0ms
    02-26 05:32:23.924: D/dalvikvm(22857): GC_CONCURRENT freed 388K, 5% free 13573K/14215K, paused 0ms+1ms
    02-26 05:32:23.974: D/LogScreenAdapter(22857): - performFiltering()
    02-26 05:32:23.983: D/LogScreenAdapter(22857): + publishResults(constraint:logs, results.count:3)
    02-26 05:32:23.983: D/LogScreenAdapter(22857): - publishResults()
    02-26 05:32:23.983: D/LogScreenAdapter(22857): + getView( position=0)
    02-26 05:32:24.074: D/LogScreenAdapter(22857): + getView( position=0)
    02-26 05:32:24.093: D/LogScreenAdapter(22857): + getView( position=0)
    02-26 05:32:24.113: D/LogScreenAdapter(22857): + getView( position=1)
    02-26 05:32:24.155: D/LogScreenAdapter(22857): + getView( position=2)
    02-26 05:32:24.164: D/LogScreenAdapter(22857): + getView( position=3)
    *** 02-26 05:32:24.193: W/LogScreenAdapter(22857): position out of bounds!
    02-26 05:32:24.233: D/LogScreenAdapter(22857): + getView( position=4)
    *** 02-26 05:32:24.263: W/LogScreenAdapter(22857): position out of bounds!
    02-26 05:32:24.284: D/LogScreenAdapter(22857): + getView( position=5)
    *** 02-26 05:32:24.313: W/LogScreenAdapter(22857): position out of bounds!
    02-26 05:32:24.333: D/LogScreenAdapter(22857): + getView( position=6)
    *** 02-26 05:32:24.343: W/LogScreenAdapter(22857): position out of bounds!
    02-26 05:32:24.353: D/LogScreenAdapter(22857): + getView( position=0)
    02-26 05:32:24.373: D/LogScreenAdapter(22857): + getView( position=1)
    02-26 05:32:24.383: D/LogScreenAdapter(22857): + getView( position=2)
    02-26 05:32:24.403: D/LogScreenAdapter(22857): + getView( position=3)
    *** 02-26 05:32:24.413: W/LogScreenAdapter(22857): position out of bounds!
    02-26 05:32:24.433: D/LogScreenAdapter(22857): + getView( position=4)
    *** 02-26 05:32:24.443: W/LogScreenAdapter(22857): position out of bounds!
    02-26 05:32:24.463: D/LogScreenAdapter(22857): + getView( position=5)
    *** 02-26 05:32:24.475: W/LogScreenAdapter(22857): position out of bounds!
    02-26 05:32:24.483: D/LogScreenAdapter(22857): + getView( position=6)
    *** 02-26 05:32:24.503: W/LogScreenAdapter(22857): position out of bounds!
    02-26 05:38:26.769: D/dalvikvm(22857): GC_CONCURRENT freed 316K, 5% free 13640K/14215K, paused 0ms+1ms
    

    What you are seeing here, the publishResults() method did change mData from a list of 7 items to a shorter list of 3 items, see the code above, but the Adapter keeps getting getView() calls for the 7 items list, even that it is not longer there.
    Note that notifyDataSetChanged() has been called with the new data assignment, so the ListView should be aware of the new list.

  • Kill all activities when HOME key is pressed android
  • My fragment cannot be cast to android.support.v4.app.Fragment
  • How to get “printf” messages written in NDK application?
  • Is there a better way to restore SearchView state?
  • Add Marker on Android Google Map via touch or tap
  • How to properly add custom view to the toolbar?
  • 3 Solutions collect form web for “Android ListView array index out of bounds after filter”

    what are you returning in public int getCount() method of custom list view adapter?

    You should return like mData != null? mData.size() : 0,

    Position out of bond is getting due to may be you are returning size of list more than data to show in the list

    getCount() method of custom list adapter specifies size of list view so it should be the size of data you are passing in the list

    Seems like overriding of “getCount()” method will solve your problem:

    @Override
    public int getCount() {
        return mData.size();
    }
    

    I did this and it solved my problems

    @Override
    public int getCount() {
    
        if (isFiltered == true) {
            return myFilteredArray.size();
        }
    
        return myUnfilteredArray.size();
    } 
    
    Android Babe is a Google Android Fan, All about Android Phones, Android Wear, Android Dev and Android Games Apps and so on.