Filtering a RecyclerView with Custom Objects.

By | May 13, 2016

This demo will show you how you can filter a RecyclerView with your Custom Objects.

If you are new to RecyclerView, then please go through this post to get a glance.

Check out the Demo Video ( 7 seconds)

RecyclerView Filter

Here I am using a CustomClass called “ListItem” which has three members.

ListItem

package com.coderzheaven.filterlistview;

public class ListItem {
    String name, place;
    int logo;

    public void setData(String name, String place, int logo) {
        this.name = name;
        this.place = place;
        this.logo = logo;
    }
}

MainActivity

package com.coderzheaven.filterlistview;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {

    private static final String TAG = "MainActivity";
    private ArrayList<ListItem> allList;

    private RecyclerView mRecyclerView;
    private MyRecyclerAdapter adapter;
    private SearchView mSearchView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mSearchView = (SearchView) findViewById(R.id.search_view);
        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);

        setList();

        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

        adapter = new MyRecyclerAdapter(this, allList);
        mRecyclerView.setAdapter(adapter);

        setupSearchView();
    }

    public void setList() {

        allList = new ArrayList<ListItem>();

        ListItem item = new ListItem();
        item.setData("Google", "USA", R.drawable.google);
        allList.add(item);

        item = new ListItem();
        item.setData("Apple", "USA", R.drawable.apple);
        allList.add(item);

        item = new ListItem();
        item.setData("Samsung", "Korea", R.drawable.samsung);
        allList.add(item);

        item = new ListItem();
        item.setData("Sony", "Japan", R.drawable.sony);
        allList.add(item);

        item = new ListItem();
        item.setData("HTC", "Taiwan", R.drawable.htc);
        allList.add(item);

        for (int i = 0; i < 10000; i++) {
            item = new ListItem();
            item.setData("Google " + i, "USA " + i, R.drawable.google);
            allList.add(item);
        }

    }

    private void setupSearchView() {
        mSearchView.setIconifiedByDefault(false);
        mSearchView.setOnQueryTextListener(this);
        mSearchView.setSubmitButtonEnabled(true);
        mSearchView.setQueryHint("Search Here");
    }

    public boolean onQueryTextChange(String newText) {
        adapter.filter(newText);
        return true;
    }

    public boolean onQueryTextSubmit(String query) {
        return false;
    }

}

We have added around 10000 custom items in the RecyclerView for searching.

Now we will see the “RecyclerView” which also includes searching.

MyRecyclerAdapter

package com.coderzheaven.filterlistview;

import android.app.Activity;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

public class MyRecyclerAdapter extends RecyclerView.Adapter<MyCustomViewHolder> {

    private List<ListItem> listItems, filterList;
    private Context mContext;

    public MyRecyclerAdapter(Context context, List<ListItem> listItems) {
        this.listItems = listItems;
        this.mContext = context;
        this.filterList = new ArrayList<ListItem>();
        // we copy the original list to the filter list and use it for setting row values
        this.filterList.addAll(this.listItems);
    }

    @Override
    public MyCustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {

        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_item, null);
        MyCustomViewHolder viewHolder = new MyCustomViewHolder(view);
        return viewHolder;

    }

    @Override
    public void onBindViewHolder(MyCustomViewHolder customViewHolder, int position) {

        ListItem listItem = filterList.get(position);
        customViewHolder.tvName.setText(listItem.name);
        customViewHolder.tvPlace.setText(listItem.place);
        customViewHolder.imgThumb.setBackgroundResource(listItem.logo);

    }

    @Override
    public int getItemCount() {
        return (null != filterList ? filterList.size() : 0);
    }
    
    // Do Search...
    public void filter(final String text) {

        // Searching could be complex..so we will dispatch it to a different thread...
        new Thread(new Runnable() {
            @Override
            public void run() {

                // Clear the filter list
                filterList.clear();

                // If there is no search value, then add all original list items to filter list
                if (TextUtils.isEmpty(text)) {

                    filterList.addAll(listItems);

                } else {
                    // Iterate in the original List and add it to filter list...
                    for (ListItem item : listItems) {
                        if (item.name.toLowerCase().contains(text.toLowerCase()) ||
                                item.place.toLowerCase().contains(text.toLowerCase())) {
                            // Adding Matched items
                            filterList.add(item);
                        }
                    }
                }

                // Set on UI Thread
                ((Activity) mContext).runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // Notify the List that the DataSet has changed...
                        notifyDataSetChanged();
                    }
                });

            }
        }).start();

    }

}

MyCustomViewHolder

package com.coderzheaven.filterlistview;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

public class MyCustomViewHolder extends RecyclerView.ViewHolder {

    protected ImageView imageView;
    protected TextView tvName, tvPlace;
    protected ImageView imgThumb;

    public MyCustomViewHolder(View view) {
        super(view);
        this.tvName = (TextView) view.findViewById(R.id.tvName);
        this.tvPlace = (TextView) view.findViewById(R.id.tvPlace);
        this.imgThumb = (ImageView) view.findViewById(R.id.imgThumb);
    }

}

You could check my RecyclerView post to check the layout XMLs and update the layout ids as well.

Download the complete Android Studio Source Code from here.

9 thoughts on “Filtering a RecyclerView with Custom Objects.

  1. dondeepak

    hai, i tried to use your code but when i open main activity page is empty but when i type something and delete in search box only after list is loading. please help

    Reply
      1. Saurabh Sarpotdar

        It is still not working…means all the items are visible only when I type something in the searchview and then clear it…and after that i can have normal implementation.. but at the start why all the items are not appearing.?

        Reply
        1. James Post author

          You can change the logic anyway you want.
          There is no value in the textbox when the app starts.

          Reply
        2. Darpan K

          Change this:

          @Override
          public int getItemCount() {
          return (null != filterList ? filterList.size() : 0);
          }

          to:

          @Override
          public int getItemCount() {
          return (null != filterList ? filterList.size() : listItems.size());
          }

          or:

          @Override
          public int getItemCount() {
          if(filterList.size() != 0)
          return filterLIst.size();
          else
          return listItems.size();
          }

          Reply
    1. Hardeep Singh

      Nice tutorial. But am facing same issue as discussed by other users. All the items are visible only when I type something in the searchview and then clear it. I think some change need to be done here:
      public int getItemCount() {
      return (null != filterList ? filterList.size() : 0);
      }
      Kindly reply. I need all the items to be displayed once fragment is created.

      Reply
      1. James Post author

        Yeah, you could change the logic based on the requirement.
        If the filtercount is zero, you could add all items in the original array list to filter list and call notifyDatasetChanged() method to view all the items.

        Reply

Leave a Reply to amin Cancel reply

Your email address will not be published. Required fields are marked *