Published Jul 31, 2020

Share this article

One of the most requested enhancements for the Random Contact App is for a way to filter contacts with the custom contact picker that is used in it. Since it seemed like a good reusable component, I added the module named MultiContactPicker along with the rearchitecture of my Andorid library project lib-aeApps.

Lets see how to add a filter for a RecyclerView in an Android app.

As you should have guessed, when we apply a filter we would show a subset of the data in the list. From the RecyclerView’s point of view, the list of data that it has to show has changed - a call to notifyDataSetChanged() is to be expected.

And where do we manage the data for a RecyclerView? The backing adapter which extends the class RecyclerView.Adapter.

  1. The first step is for the adapter to implement the android.widget.Filterable class
      class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder>
         implements Filterable {
  2. Next, we create a copy of the source data. But use the filtered list to render the view.
      private final List<ContactInfo> contactInfoList;
      private List<ContactInfo> filteredContacts;
     MyRecyclerViewAdapter(final List<ContactInfo> values) {
         filteredContacts = new ArrayList<>(values);
         contactInfoList = values;
  3. When we implementing the Filterable class, we need to add a method called getFilter(). This is where the actual filtering occurs. The performFiltering() method is passed in a search string, and we need to filter the list data based on this. The filtering criteria is upto your specific use case. I have added some optimizations so that our friend notifyDataSetChanged() is only called when required. And ofcourse when the search string is empty, we copy back the original list.
     public Filter getFilter() {
         return new Filter() {
             protected FilterResults performFiltering(CharSequence charSequence) {
                 boolean dataUpdated = false;
                 if (charSequence.length() == 0) {
                     if (filteredContacts.size() < contactInfoList.size()) {
                         filteredContacts = new ArrayList<>(contactInfoList);
                         dataUpdated = true;
                 } else {
                     filteredContacts = filterContactsByName(charSequence.toString().toLowerCase());
                     dataUpdated = true;
                 FilterResults filterResults = new FilterResults();
                 filterResults.values = dataUpdated;
                 return filterResults;
             protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
                 boolean dataUpdated = Boolean.parseBoolean(filterResults.values.toString());
                 if (dataUpdated) {
  4. Next step is to add a SearchView to the layout which includes the RecyclerView.
         app:queryHint="@string/str_multi_contact_search_hint" />
  5. And finally in the parent activity or Fragment, we respond to the QueryText of the SearchView. Whenever there is a change in text, we simply invoke the filter() method on the adapter.
      searchView = findViewById(;
      searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
       public boolean onQueryTextSubmit(String query) {
           return false;
       public boolean onQueryTextChange(String newText) {
           return false;

These are all the changes that are required. Pretty much all of the above code except the implementation for filterContactsByName() is generic and can be re-used for any project. Please reach out to me for any doubts. See the references to the source code hosted on GitHub.


  1. Random Contact App
  2. lib-aeapps
  3. MultiContactRecyclerViewAdapter
  4. Sample App