Filtering ListView with custom (object) adapter Filtering ListView with custom (object) adapter android android

Filtering ListView with custom (object) adapter


You need to do a few things:

1) In your activity, register for a text change listener on your EditText that contains the value the user enters:

mSearchValue.addTextChangedListener(searchTextWatcher);

2) Create your searchTextWatcher and have it do something:

private TextWatcher searchTextWatcher = new TextWatcher() {    @Override        public void onTextChanged(CharSequence s, int start, int before, int count) {            // ignore        }        @Override        public void beforeTextChanged(CharSequence s, int start, int count, int after) {            // ignore        }        @Override        public void afterTextChanged(Editable s) {            Log.d(Constants.TAG, "*** Search value changed: " + s.toString());            adapter.getFilter().filter(s.toString());        }    };

3) Override getFilter() in your custom adapter and have it filter the results and notify the listview that the dataset has changed.

    @Override    public Filter getFilter() {        return new Filter() {            @SuppressWarnings("unchecked")            @Override            protected void publishResults(CharSequence constraint, FilterResults results) {                Log.d(Constants.TAG, "**** PUBLISHING RESULTS for: " + constraint);                myData = (List<MyDataType>) results.values;                MyCustomAdapter.this.notifyDataSetChanged();            }            @Override            protected FilterResults performFiltering(CharSequence constraint) {                Log.d(Constants.TAG, "**** PERFORM FILTERING for: " + constraint);                List<MyDataType> filteredResults = getFilteredResults(constraint);                FilterResults results = new FilterResults();                results.values = filteredResults;                return results;            }        };    }


Here an interesting example

public Filter getFilter() {    return new Filter() {        @Override        protected FilterResults performFiltering(CharSequence constraint) {            final FilterResults oReturn = new FilterResults();            final ArrayList<station> results = new ArrayList<station>();            if (orig == null)                orig = items;            if (constraint != null) {                if (orig != null && orig.size() > 0) {                    for (final station g : orig) {                        if (g.getName().toLowerCase()                                .contains(constraint.toString()))                            results.add(g);                    }                }                oReturn.values = results;            }            return oReturn;        }        @SuppressWarnings("unchecked")        @Override        protected void publishResults(CharSequence constraint,                FilterResults results) {            items = (ArrayList<station>) results.values;            notifyDataSetChanged();        }    };}public void notifyDataSetChanged() {    super.notifyDataSetChanged();    notifyChanged = true;}


For those who don't need the Filterable interface, there is a much simpler solution. This also handles notifyDataSetChanged() correctly where the other solutions fail. Note that you need to add a getArray() function to the BaseAdapter that just returns the array object that was passed to the constructor.

public abstract class BaseFilterAdapter<T> extends BaseAdapter<T> {    private List<T> original;    private String lastFilter;    public BaseFilterAdapter(Context context, List<T> array) {        super(context, new LinkedList<T>());        original = array;        filter("");    }    protected abstract Boolean predicate(T element, String filter);    public void filter(String filter) {        lastFilter = filter;        super.getArray().clear();        for (T element : original)            if (predicate(element, filter))                super.getArray().add(element);        super.notifyDataSetChanged();    }    @Override    public List<T> getArray() {        return original;    }    @Override    public void notifyDataSetChanged() {        filter(lastFilter);    }}