androidlistviewandroid-arrayadapterandroid-filter

CustomArrayAdapter doesn't refresh after filter text has been removed


Hey guys I've implemented my own ArrayAdapter because I have two textviews in the single ListView item. While the filtering works fine(it shows the correct items), when I delete the text that I have typed to filter the items the ListView doesn't go to its initial state(it doesn't display all items), instead it just leaves the filtered list unchanged. Here is my filter implementation:

private class NightFilter extends Filter {

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        items = (ArrayList<NightOut>) results.values;
        clear();
        int count = items.size();
        for (int i = 0; i < count; i++) {
            NightOut pkmn = (NightOut) items.get(i);
            add(pkmn);
        }
    }

    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        FilterResults result = new FilterResults();
        if (constraint == null || constraint.length() == 0) {
            ArrayList<NightOut> list = new ArrayList<NightOut>(nightsOut);
            result.values = list;
            result.count = list.size();
        } else {
            final ArrayList<NightOut> list = new ArrayList<NightOut>(nightsOut);
            final ArrayList<NightOut> nlist = new ArrayList<NightOut>();
            int count = list.size();

            for (int i = 0; i < count; i++) {
                final NightOut nightOut = list.get(i);
                final String value = nightOut.getAddress().toLowerCase();

                if (value.contains(constraint.toString().toLowerCase())) {
                    nlist.add(nightOut);
                }
            }
            result.values = nlist;
            result.count = nlist.size();
        }
        return result;

    }
}

Both nightsOut and items contain the objects that i want to filter through(I assign those in the constructor). My custom adapter class extends ArrayAdapter if that's of any help.

Edit:

Added code for constructor and text filtering

    public CustomArrayAdapter(Activity context, ArrayList<NightOut> nightsOut) {
    super(context, R.layout.list_item, nightsOut);
    this.context = context;
    this.nightsOut = nightsOut;
    this.items = nightsOut;
}

Search method

        inputSearch.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
            ViewPlacesActivity.this.adapter.getFilter().filter(cs);
        }

Any idea what I'm missing?

Cheers Kyle


Solution

  • The way you are using nightsOut as the source list for your ArrayAdapter and also the source list for the filter is what is causing the problem.

    In the publishResults() method you have a call to clear() which removes all elements from the nightsOut list inside ArrayAdapter since that is the list it references. You then readd only the filtered data.

    Then the next time call performFiltering() you are using nightsOut as the source list again which only includes the filtered items.

    What you want to do instead is keep a reference to your original items. You don't really need items the way it is currently used so I would rename that to originalItems and do the following:

    public CustomArrayAdapter(Activity context, ArrayList<NightOut> nightsOut) {
        super(context, R.layout.list_item, nightsOut);
        this.context = context;
        this.nightsOut = nightsOut;
        originalItems = new ArrayList<>(nightsOut); // create a copy of nightsOut.
    }
    

    And then the filter

    private class NightFilter extends Filter {
    
        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            ArrayList<NightOut> tempList = (ArrayList<NightOut>) results.values;
            clear();
            addAll(tempList);
        }
    
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults result = new FilterResults();
            if (constraint == null || constraint.length() == 0) {
                result.values = originalItems;
                result.count = originalItems.size();
            } else {
                final ArrayList<NightOut> nlist = new ArrayList<NightOut>();
                String lowerConstraint = constraint.toString().toLowerCase();
    
                // loop through originalItems which always contains all items
                for(NightOut nightOut : originalItems) {
                    final String value = nightOut.getAddress().toLowerCase();
                    if (value.contains(lowerConstraint)) {
                        nlist.add(nightOut);
                    }
                }
    
                result.values = nlist;
                result.count = nlist.size();
            }
    
            return result;
        }
    }