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.

  • Send and Read the SMS content sent via native SMS app cordova
  • ApprtcDemo with local server works between browsers but not Android native to browser
  • Android Webview: Cannot call determinedVisibility() - never saw a connection for the pid
  • Should I inflate a layout or programmatically create it?
  • Why is App not compatible with Tablets after update
  • Android - FirebaseApp / Firebase-Initialization is not starting
  • 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.

    Related posts:

    Difference between adjustResize and adjustPan in android?
    Only the original thread that created a view hierarchy can touch its views. On android
    How To Load Layout Background Using Picasso
    Eclipse IDE - Android Graphical Layout and XML Layout Side by Side
    Android Emulator freezes
    Activity with long-lasting service in the background that will not be killed
  • Android canvas save always java.io.IOException: open failed: ENOENT (No such file or directory)
  • OnUp event on GestureDetector
  • Java MTP library that works on Windows
  • Full Android support for OSGi bundles
  • Theme.AppCompat.Light.DarkActionBar - No resource found
  • ButterKnife onclick is not working
  • 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.