Earlier I have written few articles about RecyclerView. Combining it with CardView, cloning Gmail inbox, adding Swipe to delete functionality and bunch of other.

Today, in this article we are going to learn how to add search filter functionality to RecyclerView. Adding search is very simple task, we’ll use Toolbar’s search widget to input the search query. To demonstrate I am taking an example of contacts list and search for a contact by name or phone number.

android-recyclerview-search-filter

1. RecyclerView Search Filter – getFilter()

Android provides Filterable class to filter the data by a filter (condition). Usually the getFilter() method has to be overridden in the adapter class in which the filter condition is provided to search through a list. Below is an example of getFilter() method to search a contact by name or phone number from a list of contacts.

@Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence charSequence) {
                String charString = charSequence.toString();
                if (charString.isEmpty()) {
                    contactListFiltered = contactList;
                } else {
                    List<Contact> filteredList = new ArrayList<>();
                    for (Contact row : contactList) {

                        // name match condition. this might differ depending on your requirement
                        // here we are looking for name or phone number match
                        if (row.getName().toLowerCase().contains(charString.toLowerCase()) || row.getPhone().contains(charSequence)) {
                            filteredList.add(row);
                        }
                    }

                    contactListFiltered = filteredList;
                }

                FilterResults filterResults = new FilterResults();
                filterResults.values = contactListFiltered;
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
                contactListFiltered = (ArrayList<Contact>) filterResults.values;

                // refresh the list with filtered data
                notifyDataSetChanged();
            }
        };
    }

2. Example JSON

For this example I am going to use the json from below url. This json contains list of contacts and each contact will have name, phone number and profile image.

https://api.androidhive.info/json/contacts.json

[{
		"name": "Tom Hardy",
		"image": "https://api.androidhive.info/json/images/tom_hardy.jpg",
		"phone": "(541) 754-3010"
	},
	{
		"name": "Johnny Depp",
		"image": "https://api.androidhive.info/json/images/johnny.jpg",
		"phone": "(452) 839-1210"
	}
]

3. Creating New Project

Now we’ll start with a new project in Android Studio and see how to get the desired search output.

1. Create a new project in Android Studio from File β‡’ New Project and select Basic Activity from templates.

2. Open build.gradle under app folder and add RecyclerView, Glide and Volley dependencies.

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    // ...

    // recycler view
    implementation 'com.android.support:recyclerview-v7:26.1.0'

    // glide image library
    implementation 'com.github.bumptech.glide:glide:4.3.1'

    // volley http library
    implementation 'com.android.volley:volley:1.0.0'
    implementation 'com.google.code.gson:gson:2.6.2'

}

3. Add the below resources to respective strings.xml, dimens.xml, colors.xml files.

<resources>
    <string name="app_name">RecyclerView Search</string>
    <string name="action_settings">Settings</string>
    <string name="toolbar_title">Contacts</string>
    <string name="action_search">Search</string>
    <string name="search_hint">Type name…</string>
</resources>
<resources>
    <dimen name="fab_margin">16dp</dimen>
    <dimen name="activity_margin">16dp</dimen>
    <dimen name="thumbnail">40dp</dimen>
    <dimen name="row_padding">10dp</dimen>
    <dimen name="contact_name">15dp</dimen>
    <dimen name="contact_number">12dp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#111</color>
    <color name="colorPrimaryDark">#FFF</color>
    <color name="colorAccent">#ea3732</color>
    <color name="contact_name">#333333</color>
    <color name="contact_number">#8c8c8c</color>
</resources>

4. Download this res.zip and add the drawables to your project’s res folder. These folders contains search icon needed for the toolbar.

5. Create a class named MyApplication.java and extend the class from Application. This is a singleton class in which volley is initiated.

package info.androidhive.recyclerviewsearch;

/**
 * Created by ravi on 16/11/17.
 */

import android.app.Application;
import android.text.TextUtils;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;

public class MyApplication extends Application {

    public static final String TAG = MyApplication.class
            .getSimpleName();

    private RequestQueue mRequestQueue;

    private static MyApplication mInstance;

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }

    public static synchronized MyApplication getInstance() {
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }

        return mRequestQueue;
    }

    public <T> void addToRequestQueue(Request<T> req, String tag) {
        // set the default tag if tag is empty
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);
    }

    public <T> void addToRequestQueue(Request<T> req) {
        req.setTag(TAG);
        getRequestQueue().add(req);
    }

    public void cancelPendingRequests(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }
}

6. Open AndroidManifest.xml and add MyApplication to <application> tag. Also add the INTERNET permission as we are going to make http calls.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.androidhive.recyclerviewsearch">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:name=".MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

7. As we need to parse the json, we need a POJO class to serialize the json. Create a class named Contact.java and add name, image and phone number.

package info.androidhive.recyclerviewsearch;

/**
 * Created by ravi on 16/11/17.
 */

public class Contact {
    String name;
    String image;
    String phone;

    public Contact() {
    }

    public String getName() {
        return name;
    }

    public String getImage() {
        return image;
    }

    public String getPhone() {
        return phone;
    }
}

8. Create a class named MyDividerItemDecoration.java. This step is completely optional but to add some margin to RecyclerView divider. This is a custom divider class to add left margin to divider line.

package info.androidhive.recyclerviewsearch;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
import android.view.View;

/**
 * Created by ravi on 17/11/17.
 */

public class MyDividerItemDecoration  extends RecyclerView.ItemDecoration {

    private static final int[] ATTRS = new int[]{
            android.R.attr.listDivider
    };

    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;

    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;

    private Drawable mDivider;
    private int mOrientation;
    private Context context;
    private int margin;

    public MyDividerItemDecoration(Context context, int orientation, int margin) {
        this.context = context;
        this.margin = margin;
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
        setOrientation(orientation);
    }

    public void setOrientation(int orientation) {
        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
            throw new IllegalArgumentException("invalid orientation");
        }
        mOrientation = orientation;
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            drawVertical(c, parent);
        } else {
            drawHorizontal(c, parent);
        }
    }

    public void drawVertical(Canvas c, RecyclerView parent) {
        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left + dpToPx(margin), top, right, bottom);
            mDivider.draw(c);
        }
    }

    public void drawHorizontal(Canvas c, RecyclerView parent) {
        final int top = parent.getPaddingTop();
        final int bottom = parent.getHeight() - parent.getPaddingBottom();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top + dpToPx(margin), right, bottom - dpToPx(margin));
            mDivider.draw(c);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        }
    }

    private int dpToPx(int dp) {
        Resources r = context.getResources();
        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()));
    }
}

4. Writing the Adapter class with Filter

Now as the resources ready, let’s start writing the adapter class. You need to particularly focus on this class as it is main component in this article.

9. Create a layout named user_row_item.xml and add the below layout. This layout renders the single contact item in the list. This layout contains two TextViews to render name, phone number and an ImageView to display the profile image.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?attr/selectableItemBackground"
    android:clickable="true"
    android:paddingBottom="@dimen/row_padding"
    android:paddingLeft="@dimen/activity_margin"
    android:paddingRight="@dimen/activity_margin"
    android:paddingTop="@dimen/row_padding">

    <ImageView
        android:id="@+id/thumbnail"
        android:layout_width="@dimen/thumbnail"
        android:layout_height="@dimen/thumbnail"
        android:layout_centerVertical="true"
        android:layout_marginRight="@dimen/row_padding" />

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/thumbnail"
        android:fontFamily="sans-serif-medium"
        android:textColor="@color/contact_name"
        android:textSize="@dimen/contact_name" />

    <TextView
        android:id="@+id/phone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/name"
        android:layout_toRightOf="@id/thumbnail"
        android:textColor="@color/contact_number"
        android:textSize="@dimen/contact_number" />

</RelativeLayout>

10. Create class named ContactsAdapter.java and implement the class from Filterable which asks you to override the getFilter() method.

> In getFilter() method, the search string is passed to performFiltering() method. The search for a contact by name or mobile number is performed using query string.

> You will have to adjust the search condition depending on your app requirement.

> ContactsAdapterListener interface provides onContactSelected() callback method whenever a contact is selected from the list.

package info.androidhive.recyclerviewsearch;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;

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

/**
 * Created by ravi on 16/11/17.
 */

public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.MyViewHolder>
        implements Filterable {
    private Context context;
    private List<Contact> contactList;
    private List<Contact> contactListFiltered;
    private ContactsAdapterListener listener;

    public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView name, phone;
        public ImageView thumbnail;

        public MyViewHolder(View view) {
            super(view);
            name = view.findViewById(R.id.name);
            phone = view.findViewById(R.id.phone);
            thumbnail = view.findViewById(R.id.thumbnail);

            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // send selected contact in callback
                    listener.onContactSelected(contactListFiltered.get(getAdapterPosition()));
                }
            });
        }
    }


    public ContactsAdapter(Context context, List<Contact> contactList, ContactsAdapterListener listener) {
        this.context = context;
        this.listener = listener;
        this.contactList = contactList;
        this.contactListFiltered = contactList;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.user_row_item, parent, false);

        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, final int position) {
        final Contact contact = contactListFiltered.get(position);
        holder.name.setText(contact.getName());
        holder.phone.setText(contact.getPhone());

        Glide.with(context)
                .load(contact.getImage())
                .apply(RequestOptions.circleCropTransform())
                .into(holder.thumbnail);
    }

    @Override
    public int getItemCount() {
        return contactListFiltered.size();
    }

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence charSequence) {
                String charString = charSequence.toString();
                if (charString.isEmpty()) {
                    contactListFiltered = contactList;
                } else {
                    List<Contact> filteredList = new ArrayList<>();
                    for (Contact row : contactList) {

                        // name match condition. this might differ depending on your requirement
                        // here we are looking for name or phone number match
                        if (row.getName().toLowerCase().contains(charString.toLowerCase()) || row.getPhone().contains(charSequence)) {
                            filteredList.add(row);
                        }
                    }

                    contactListFiltered = filteredList;
                }

                FilterResults filterResults = new FilterResults();
                filterResults.values = contactListFiltered;
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
                contactListFiltered = (ArrayList<Contact>) filterResults.values;
                notifyDataSetChanged();
            }
        };
    }

    public interface ContactsAdapterListener {
        void onContactSelected(Contact contact);
    }
}

5. Adding Search Widget and Filtering List

Now everything is ready. All we have to do is, enable SearchView in Toolbar, render the RecyclerView by parsing the json and pass the search query to adapter.

11. Open / create menu_main.xml located under res β‡’ menus and add the SearchView widget and make it always visible.

12. Under res β‡’ xml folder, create an xml file named searchable.xml (If xml folder doesn’t exists, create a new one)

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:hint="@string/search_hint"
    android:label="@string/app_name" />

13. Open AndroidManifest.xml and configure the search as shown below.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.androidhive.recyclerviewsearch">

    <uses-permission android:name="android.permission.INTERNET" />

    <application ...>
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">

            <meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchable" />

            <intent-filter>
                <action android:name="android.intent.action.SEARCH" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

14. Open the layout files of main activity activity_main.xml and content_main.xml and add RecyclerView element.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="info.androidhive.recyclerviewsearch.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@android:color/white"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

</android.support.design.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="info.androidhive.recyclerviewsearch.MainActivity"
    tools:showIn="@layout/activity_main">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical" />

</RelativeLayout>

15. Finally open the MainActivity.java and add the code as shown below.

> In fetchContacts() method a volley is request is made to fetch the json. The fetched json is searialized using Gson and all the contacts were added to a list. Calling mAdapter.notifyDataSetChanged() renders the RecyclerView.

> In onCreateOptionsMenu() the menu is inflated and SearchView is displayed.

> searchView.setOnQueryTextListener() listens to character changes while user typing in search filed. The entered query then passed to adapter class using mAdapter.getFilter().filter(query), then the RecyclerView is refreshed with filtered data.

> onContactSelected() will be called when a contact is selected from the list.

package info.androidhive.recyclerviewsearch;

import android.app.SearchManager;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import org.json.JSONArray;

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

public class MainActivity extends AppCompatActivity implements ContactsAdapter.ContactsAdapterListener {
    private static final String TAG = MainActivity.class.getSimpleName();
    private RecyclerView recyclerView;
    private List<Contact> contactList;
    private ContactsAdapter mAdapter;
    private SearchView searchView;

    // url to fetch contacts json
    private static final String URL = "https://api.androidhive.info/json/contacts.json";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        // toolbar fancy stuff
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setTitle(R.string.toolbar_title);

        recyclerView = findViewById(R.id.recycler_view);
        contactList = new ArrayList<>();
        mAdapter = new ContactsAdapter(this, contactList, this);

        // white background notification bar
        whiteNotificationBar(recyclerView);

        RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.addItemDecoration(new MyDividerItemDecoration(this, DividerItemDecoration.VERTICAL, 36));
        recyclerView.setAdapter(mAdapter);

        fetchContacts();
    }

    /**
     * fetches json by making http calls
     */
    private void fetchContacts() {
        JsonArrayRequest request = new JsonArrayRequest(URL,
                new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        if (response == null) {
                            Toast.makeText(getApplicationContext(), "Couldn't fetch the contacts! Pleas try again.", Toast.LENGTH_LONG).show();
                            return;
                        }

                        List<Contact> items = new Gson().fromJson(response.toString(), new TypeToken<List<Contact>>() {
                        }.getType());

                        // adding contacts to contacts list
                        contactList.clear();
                        contactList.addAll(items);

                        // refreshing recycler view
                        mAdapter.notifyDataSetChanged();
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // error in getting json
                Log.e(TAG, "Error: " + error.getMessage());
                Toast.makeText(getApplicationContext(), "Error: " + error.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });

        MyApplication.getInstance().addToRequestQueue(request);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);

        // Associate searchable configuration with the SearchView
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        searchView = (SearchView) menu.findItem(R.id.action_search)
                .getActionView();
        searchView.setSearchableInfo(searchManager
                .getSearchableInfo(getComponentName()));
        searchView.setMaxWidth(Integer.MAX_VALUE);

        // listening to search query text change
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                // filter recycler view when query submitted
                mAdapter.getFilter().filter(query);
                return false;
            }

            @Override
            public boolean onQueryTextChange(String query) {
                // filter recycler view when text is changed
                mAdapter.getFilter().filter(query);
                return false;
            }
        });
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_search) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onBackPressed() {
        // close search view on back button pressed
        if (!searchView.isIconified()) {
            searchView.setIconified(true);
            return;
        }
        super.onBackPressed();
    }

    private void whiteNotificationBar(View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            int flags = view.getSystemUiVisibility();
            flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
            view.setSystemUiVisibility(flags);
            getWindow().setStatusBarColor(Color.WHITE);
        }
    }

    @Override
    public void onContactSelected(Contact contact) {
        Toast.makeText(getApplicationContext(), "Selected: " + contact.getName() + ", " + contact.getPhone(), Toast.LENGTH_LONG).show();
    }
}
android-recyclerview-search-filter

I hope this article explains very well about filtering the RecyclerView data. If you still have any queries, let’s discuss them in the comment section below.

Happy Coding πŸ˜€

Hi there! I am Founder at androidhive and programming enthusiast. My skills includes Android, iOS, PHP, Ruby on Rails and lot more. If you have any idea that you would want me to develop? Let’s talk: ravi@androidhive.info
  • Jay Patel

    today made recyclerview with filter app everything working fine but problem is occurred when i search some word and getting result correct but when on click filter result list it old position get
    can u help me

    • Do you want position of the element? I have written a callback which returns the actual object instead of position.

      If you want position, you can use .indexOf() method.

  • Josee Naava

    exelente

  • Al tegani

    hi Ravi Thanks

  • Gokul Krish

    with rxjava it could be easy..

    • Giving a code example would be helpful to others.

  • Ramanpreet Singh

    after writing some text in search and press go button on soft keyboard give error of null itemCountSize in adapter. What to do?

    • Can you paste the error from LogCat.

      • Ramanpreet Singh

        Thanks for replying Ravi… Your given code works perfectly fine but there is a minor issue, on pressing go, your activity just restarted and but in my application, I am getting list through intent which when on pressed go button restarts the activity and so gives null error. So I solve this problem by hiding the softkeybord on pressing go button after writing some text in searchview.

        • Cool. Please share the code you have added.

  • Have you tried extending your class from SugarApp instead of Application?

    • Sugar extends Application for default

  • Dilshad Khan

    Thanks @ravi8x:disqus and bro i want to ask a question i’m try to do search view with fragments using viewpager (Tabs) so tell me how to do this.

    https://uploads.disquscdn.com/images/c2f17055bcad52d1d2c5151ad26a03b65b4455d32ff1d2024624396a11fd33d7.gif

  • Amar Ilindra

    I’m getting this error “java.lang.IndexOutOfBoundsException: Inconsistency detected.” when using search on large data (like 200 rows)

  • I think some Contact name is array list is null.

    • Dilshad Khan

      yes u r right Ravi i solved my problem…

      Bro Ravi i want to give u a task…
      make an app that load large json file about 2000+ rows or more
      and load it into app…

      actually i searched everywhere but didn’t get any solution to fetching large json data into app….
      my question is that – i want to fetch first 50 items and when user scroll down & user reach at last item of recyclerView i want to show loading spinner and than load next 50 items…
      Like Google Playstore

      if u do this its really v.helpfull for Android beginners like me ^_^
      and one more thing really you are doing great work. when i’m facing error or want something new in app i just open open Androidhive because there is @ravi8x:disqus ^_^

      • Nur Muhammad

        Maybe you can configure your server to able getting data with pagination parameter (page 1, 2, etc…). And then in your android app you can use RecyclerView Endless Scrolling to load more data.

  • juna.binrusdi

    Hii Ravi,,,tq so much

  • Dharmendra Mishra

    Thank you so much Sir ji πŸ™‚

  • Parth Aggarwal

    Sir Please share this whole code in Kotlin Android also.

  • Atharva Unde

    Can u make a detailed tutorial on google transport tracking system ?

  • Email Subjekt

    Hi Ravi, thank you for the code! Is there a way to use this in a fragment?

  • Roeun Chhengheng

    Thank you for this code! If I want to use json for offline, what can i do?

  • ahmed azeema

    thank u Ravi but how can i make detail activity onclick ?

  • Juliet Wanjohi

    @ravi8x:disqus Hi, I have been able to make the search view work on my paginated recyclerview. However, the user is only able to get a search result after loading all the pages in the recyclerview. How do I make a search result return even if only one page has been loaded?

    • Then the search has to be done on the server instead of local. You can send the search query to sever and perform search there, return the results.

  • Jerry Yu

    For whatever reason, we have to call searchView.setIconified(true) twice to iconify the searchView. This information could be useful for other readers.

  • nikul

    this.contactList = contactList;
    this.contactListFiltered = contactList;
    both refer to the same memory location then why need extra variable

  • Sharath

    i am getting null pointer exception????

  • Is the device has Internet connection?

    • Sharath

      yes

      • See if the json is fetched correctly from server. Print some Logs and check.

  • le anhvu

    thank you so much

  • Programmer Java

    thank you so much..
    I can Use this code with php and database?

    • Yes, you need to build Rest api for search endpoint.

  • Aviv Zikel

    I have node.js server, is it possible to connect it to the search option? I mean that the results of the searching(in the search view) will be shown from the db which connected to the node.js server

  • Aditi Gupta

    Hi Ravi….this is the great article.
    My question is I am trying to integrate alphabet side index with this article to make it like contact list in our phone,but I am unable to do it.Can you please help?

  • Geneva Daugdaug

    Attempt to invoke interface method ‘int java.util.List.size()’ on a null object reference.

    I have this error.

    • What is the code at error line. You can find the file name along with file name in LogCat.

  • Kevin Moses Kenap

    Hello bro, i wanna ask you, if the data in this tutorial retrieve from firebase database can you teach me how?

  • Jayaprakash

    Hi bro, This code is working like charm but the issue was if I access from the local database its showing the result if I do with the API response its not at all filtering

    • Wherever the data is coming from, it will be in ArrayList only. So it should work. Is API response is fetch each time something is typed in search?

  • Jojo

    Thank you

  • Ashis Ranjan Dey

    does this search work if I search with lastname or middlename?

    • That depends on the logic you are writing in adapter class. Check getFilter() method in adapter class.

  • Daily Wiki

    Want to load Webview on Click, could someone please help with that I m new to android studio

  • Karthikesavan

    For me the code works till, when i type the text in search box, i can able to toast the letter on each change, but in your code you have used gson, but in mine its StringRequest, so im stuck in this point, so how to go further? any suggestions? https://uploads.disquscdn.com/images/02ec17eb2436cd222a761b059ed7b0cc03f054d328e1277a22a869e02bfe7c9d.png

  • Alaa_Alshorbagy

    Hi Ravi Tamada
    i have an exception happened in performFiltering() function
    “Java.util.ConcurrentModificationException”
    and this lead me to this line of code in ContactsAdapter class and
    my code match your code and after search found it’s prefer to use Iterator when add or remove in arrayList
    and change this segment of code to using iterator and the same exception happen
    please any help
    thanks for you time.

    exception happen here —>>> for (Contact row : contactList) {

    // name match condition. this might differ depending on your requirement
    // here we are looking for name or phone number match
    if (row.getName().toLowerCase().contains(charString.toLowerCase()) || row.getPhone().contains(charSequence)) {
    filteredList.add(row);
    }
    }

    • dwi

      i have error like this to

      • Post your complete error report along with Adapter class code.

  • Alaa_Alshorbagy

    Hi Ravi Tamada,
    as per your code when i press on submit search view display filtered names only ok?
    but when you press on submit search view it display all contacts
    or how to do this ?

  • dwi

    thanks for your tutorial, but i have error on Filter Results
    for(Contact row : contactList)
    the error is row must be Object type.
    what sould i do?

  • Hi Amrit

    These are static JSON files created for article demonstrations. If you want to build the JSON from a database, read the below article.
    https://www.androidhive.info/2014/01/how-to-create-rest-api-for-android-app-using-php-slim-and-mysql-day-12-2/

  • Josee Naava

    How do you add empty state when there are no results?

    • Easier way to place Empty state view on top of RecyclerView and show it when the result set size is 0. The other way is, having empty state as a row in RecyclerView itself and show it when there is no data. But this approach a bit difficult and it needs lot of changes in Adapter class.

  • LakshmiRao Burugula

    Hello Ravi, thank you for this amazing post. I want to search support for Arabic RTL. In the Manifest you did mention “android:supportsRtl=”true”” but search view looks the same as English on Arabic language. I have included the screenshot of search in Arabic, search icon and the cursor should start from the right when we start to type. Could you please guide on how to get that working please

  • Rizky Nofriwandi

    Hai Ravi,
    Thank u for you amazing Post
    i follow your tutorial but when i’m trying search it give me the correct result but when i delete the Text on SearchView recyclerview not back to view All the Data..

    Can u tell me where’s my mistake?

    https://uploads.disquscdn.com/images/cc2cff332ec2d37188084ebd63eb6fe93b6940eb677bacbc09898ea564c2fc29.png https://uploads.disquscdn.com/images/57226a491c37097624b7f39e09d77c104ff70253b26395dbb7642c60323cea95.png https://uploads.disquscdn.com/images/ea0a601ba353714c024f3c3b38a4e1f5b53d07fa5fc3f7f3adcb64bc9d179319.png

  • AN

    Hi, I tried your code, it always displays only the first item in the recycler view, irrespective of what I search for. I can’t figure out where I might’ve gone wrong?

    • Check the adapter class. You might have used wrong array list while searching.

    • Ebenezer Agyemang Sakyi

      Where you able to solve it? Facing the same issue

  • Hardik sharma

    Hey Ravi how to use the back arrow button in this search view.

  • redlynxks
  • Anele

    I want to load a CallIntent and SmsIntent when you have selected a contact on this line of code on the Mainactivity.java

    @Override
    public void onContactSelected(Contact contact) {
    Toast.makeText(getApplicationContext(), “Selected: ” + contact.getName() + “, ” + contact.getPhone(), Toast.LENGTH_LONG).show();
    }

  • Duhamel

    Thanks to you, I finally done it after wasting a whole weekend on the official doc.
    Thank you

  • OmkarK

    You with your every Tutorial Put a Smile on my Face πŸ˜€ …! Thank you for sharing such valuable Knowledge.. πŸ™‚

    • I am glad the blog is helping you πŸ™‚

      All the best!

  • Ebenezer Agyemang Sakyi

    Hi, I tried your code, it always displays only the first item in the recycler view, irrespective of what I search for. I can’t figure out where I might’ve gone wrong?

    • Verify your getfilter method in adapter. You might be accessing wrong array list.

      • Joseph Joey

        I am getting the same problem in both response list and search result even after replacing my adapter code with yours

  • Chris

    great tutorial, thanks. Very helpful – a few little tweaks I had to make but got it working. Would be useful to add above I think that you could also create the json to be filtered from a php file – which creates the JSON dynamically. As far as I know this is the only very up-to-date tutorial for what it sets out to acheive – I mean it uses Volley and recyclerView. All others I saw – use asynctask/ httpConnection/listview etc…

  • Mohammad Ali Kadiwala

    i have no any JSON data so can i use this for a any one like i have a static data so ?

  • Joseph Joey

    Hi Ravi, I am getting only one item in both the response list in activity and search result list even after replacing my adapter code with yours. What went wrong?

  • richard

    Nice tutorial worked for me

  • Alyona Rodina

    πŸ™ this is my second tutorial I try here. Nothing works for me

    • Have you tried basic RecyclerView?

      • Alyona Rodina

        Thank you for the response. Could you please advice me which basic RecycleView?

  • Max V

    Thanks! Very good example! Question. Is there a limit to the number of entries? will like 20,000?

    • Why do wanna display 20000 lines in RecyclerView?

      • Max V

        because I see the great potential of this example. can be as a reference or a database replacement.

        • Usually if we load the RecyclerView with huge data, you might be get Outofmemory exception.

          • Tuga Dyrdek

            Imaging the example above but with worldwide radio stations. Any suggestion? I was thinking to start with an empty list and only when the user enters the first letter it searches but I don’t know if I can do that. And even if I can it might still be too much data.

          • You can use database (may be Room) to store the data temporarily and show it in list.

          • Tuga Dyrdek

            I will give it a try. Thanks.

          • Ashish Yadav

            Generally how many items a RecyclerView can store? For Example, in your example, how many contacts can be loaded?

          • That usually depends on the data you are loading and the way it’s loaded. If it’s having large bitmaps, you will see outOfMemory exceptions. It also effects the performance. If your list is having large data set, consider using Paging on the data.

            https://developer.android.com/topic/libraries/architecture/paging.html

  • Alejandro Dominguez

    Excelente ejemplo amigo. Gracias por el aporte!

  • mavilla vishnu vardhan

    Forgot to add this line in proguard and so my release apk was crashing due to class not found exception. Home this helps someone:

    -keep class android.support.v7.widget.SearchView { *; }

  • Aditya

    Hey Ravi, I implemented your code but when I search for an item in my recyclerView it returns the correct number of items but their positions are not updated and it returns the previous items already present in the view.

    • Make sure you cleared the array list and used correct one in getFilter method.

  • juan felipe rueda roman

    Thanks Ravi nice tutorial, i have a question, im planing on implement the search with a custom searchview on my activity(my own edit text and search icon) i wonder if i just have to instantiate the searchview in my onCreate instead of in the onCreateOptions menu the same with the query listener and thats it or i should have in count other things

  • Jasur

    Thanx) I call this list from fragment. and I need to pass data from chosen item to back to the fragment. can u help me?

    • Can you try using interface with callback methods?

  • arefi mohammad

    what recyclerview in android?

  • ankit dubey

    tell me please, how to change app bar and status bar background color to white, and its text color to black.

    • Hi

      You question is already explained in the same article. You can notice the white app bar and toolbar in the screenshots.

  • Sachin Dodti

    Sir Make a tutorial on MVP Architecture

  • Sugam Pradhan

    Hello Amazing tutorial,
    But i m getting nullpointerexception on contactListFiltered.
    Note: I get this exception when i try to enter keywords in search and press search button.

  • Mitesh Makwana

    is there any way to display particular item only once in recycler view?

  • Saket Mayank

    I want to use search view widget just above the recyclerview within the layout and not in the toolbar.

    • You can just add an EditText above RecyclerView. Add on text change listener to EditText and perform the same search query.

      • Saket Mayank

        Like this

        search.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {

        }
        });

        • Yes. Call mAdapter.getFilter().filter(query); inside onTextChanged


          search.addTextChangedListener(new TextWatcher() {
          @Override
          public void beforeTextChanged(CharSequence s, int start, int count, int after) {

          }

          @Override
          public void onTextChanged(CharSequence s, int start, int before, int count) {
          mAdapter.getFilter().filter(query);
          }

          @Override
          public void afterTextChanged(Editable s) {

          }
          });

          • Saket Mayank

            It’s not working ,I dont know why . I am implementing this inside a fragment

          • Post your Fragment Code.

          • Saket Mayank

            public class DiscussionForum extends Fragment implements ForumAdapter.ForumAdapterListener {
            // TODO: Rename parameter arguments, choose names that match
            // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
            private static final String ARG_PARAM1 = “param1”;
            private static final String ARG_PARAM2 = “param2”;

            // TODO: Rename and change types of parameters
            private String mParam1;
            private String mParam2;
            private TextView socname;
            private EditText messageinput;
            private EditText search;
            SearchView searchView;
            private FloatingActionButton messagesend;
            ProgressDialog progressDialog;
            private static final String TAG = “Discussion Forum”;
            private RecyclerView recyclerView;
            private List forumlist;
            private ForumAdapter mAdapter;
            private OnFragmentInteractionListener mListener;
            private LinearLayout list;
            private String sendurl,geturl;
            public DiscussionForum() {
            // Required empty public constructor
            }

            /**
            * Use this factory method to create a new instance of
            * this fragment using the provided parameters.
            *
            * @param param1 Parameter 1.
            * @param param2 Parameter 2.
            * @return A new instance of fragment DiscussionForum.
            */
            // TODO: Rename and change types and number of parameters
            public static DiscussionForum newInstance(String param1, String param2) {
            DiscussionForum fragment = new DiscussionForum();
            Bundle args = new Bundle();
            args.putString(ARG_PARAM1, param1);
            args.putString(ARG_PARAM2, param2);
            fragment.setArguments(args);
            return fragment;
            }

            @Override
            public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
            }
            }

            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            View view = inflater.inflate(R.layout.fragment_discussion_forum, container, false);
            onButtonPressed(“Discussion Forum”);
            socname = view.findViewById(R.id.society_name);
            // messageinput=view.findViewById(R.id.messageinput);
            messagesend=view.findViewById(R.id.sendmessage);
            forumlist = new ArrayList();
            recyclerView=view.findViewById(R.id.listviewforum);
            list=view.findViewById(R.id.list);
            search=view.findViewById(R.id.search);
            int resId = R.anim.layout_animation_fall_down;
            LayoutAnimationController animation = AnimationUtils.loadLayoutAnimation(getContext(), resId);
            mAdapter = new ForumAdapter(getContext(), forumlist, this);
            RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getContext());
            recyclerView.setLayoutManager(mLayoutManager);
            recyclerView.setLayoutAnimation(animation);
            recyclerView.setAdapter(mAdapter);
            progressDialog = new ProgressDialog(getContext());
            progressDialog.setCancelable(false);
            String uid = getActivity().getIntent().getStringExtra(“type”);

            geturl=””;

            fetchforumdata(getActivity().getIntent().getStringExtra(“id”));
            messagesend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            opendialog();
            }
            });

            search.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            mAdapter.getFilter().filter(s);
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
            });
            return view;
            }

            private void fetchforumdata(final String id1) {
            Log.e(“url”,geturl+id1);
            progressDialog.setMessage(“Loading…”);
            showDialog();
            StringRequest request = new StringRequest(Request.Method.GET,
            geturl+id1,
            new Response.Listener() {
            @Override
            public void onResponse(String response) {
            // Log.d(“tag2”,”id”+id1);
            Log.d(TAG, “Response Prop: ” + response.toString());
            hideDialog();
            try{
            JSONObject jObj = new JSONObject(response);
            boolean error = jObj.getBoolean(“errors”);
            if(!error){
            JSONObject dataobj = jObj.getJSONObject(“data”);
            JSONArray ticketarray = dataobj.getJSONArray(“result”);
            if(ticketarray.length()== 0){
            list.setVisibility(View.VISIBLE);
            }
            else{
            recyclerView.setVisibility(View.VISIBLE);
            List items = new Gson().fromJson(ticketarray.toString(), new TypeToken<List>() {
            }.getType());

            forumlist.clear();
            forumlist.addAll(items);
            mAdapter.notifyDataSetChanged();}
            }
            else{
            // String errorMsg = jObj.getString(“error_msg”);
            Toast.makeText(getContext(),
            “Try again or report an issue”, Toast.LENGTH_LONG).show();
            }
            }
            catch (JSONException e) {
            e.printStackTrace();
            }

            }
            }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
            // error in getting json
            Log.e(TAG, “Error: ” + error.getMessage());
            Toast.makeText(getContext(), “Error: ” + error.getMessage(), Toast.LENGTH_SHORT).show();
            hideDialog();
            }
            });

            MyApplication.getInstance().addToRequestQueue(request);
            }

            // TODO: Rename method, update argument and hook method into UI event
            public void onButtonPressed(String title) {
            if (mListener != null) {
            mListener.onFragmentInteraction(title);
            }
            }

            @Override
            public void onAttach(Context context) {
            super.onAttach(context);
            if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
            } else {
            throw new RuntimeException(context.toString()
            + ” must implement OnFragmentInteractionListener”);
            }
            }

            @Override
            public void onDetach() {
            super.onDetach();
            mListener = null;
            }
            private void showDialog() {
            if (!progressDialog.isShowing())
            progressDialog.show();
            }

            private void hideDialog() {
            if (progressDialog.isShowing())
            progressDialog.dismiss();
            }
            @Override
            public void onDocumentSelected(String id, String username, String created_at, String user_id, String flattitle, String message) {

            }

            public interface OnFragmentInteractionListener {
            // TODO: Update argument type and name
            void onFragmentInteraction(String title);
            }
            }

          • Saket Mayank

            This is the Adapter Class Code

            public class ForumAdapter extends RecyclerView.Adapter implements Filterable {
            private Context context;
            private List ticketlist;
            private List filterlist;
            private ForumAdapterListener listener;

            public class MyViewHolder extends RecyclerView.ViewHolder {
            TextView username,createdat,forummessage,flatno,category;
            ImageView edit;

            public MyViewHolder(View view) {
            super(view);
            username=view.findViewById(R.id.user_name2);
            createdat=view.findViewById(R.id.date2);
            edit = view.findViewById(R.id.profile_icon2);
            forummessage=view.findViewById(R.id.forum_message);
            flatno=view.findViewById(R.id.flat_no);
            category=view.findViewById(R.id.category);

            }
            }
            public ForumAdapter(Context context, List ticketlist, ForumAdapterListener listener) {
            this.context = context;
            this.listener = listener;
            this.ticketlist = ticketlist;
            this.filterlist=ticketlist;
            }

            @Override
            public ForumAdapter.MyViewHolder onCreateViewHolder( ViewGroup parent, int viewType) {
            View itemView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.discussion_forum_item, parent, false);

            return new MyViewHolder(itemView);
            }

            @Override
            public void onBindViewHolder( ForumAdapter.MyViewHolder holder, int position) {
            final ForumData contact = ticketlist.get(position);
            holder.username.setText(contact.getUsername());
            holder.flatno.setText(contact.getFlattitle());
            holder.forummessage.setText(contact.getMessage());
            holder.createdat.setText(contact.getCreated_at());
            holder.category.setText(contact.getCategory());
            Glide.with(context)
            .load(“https://studphotos.s3/”+contact.getUser_id()+”.jpg”)
            .apply(new RequestOptions().circleCrop().placeholder(R.drawable.man).error(R.drawable.man))
            .into(holder.edit);
            holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            listener.onDocumentSelected(contact.getId(),contact.getUsername(),contact.getCreated_at(),contact.getUser_id(),contact.getFlattitle(),contact.getMessage());
            }
            });

            }

            @Override
            public int getItemCount() {
            return ticketlist.size();
            }

            @Override
            public Filter getFilter() {
            return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence charSequence) {
            String charString = charSequence.toString();
            if (charString.isEmpty()) {
            filterlist = ticketlist;
            } else {
            List filteredList = new ArrayList();
            for (ForumData row : ticketlist) {

            // name match condition. this might differ depending on your requirement
            // here we are looking for name or phone number match
            if (row.getUsername().toLowerCase().contains(charString.toLowerCase()) || row.getCategory().contains(charSequence)) {
            filteredList.add(row);
            }
            }

            filterlist = filteredList;
            }

            FilterResults filterResults = new FilterResults();
            filterResults.values = filterlist;
            return filterResults;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
            filterlist = (ArrayList) results.values;
            notifyDataSetChanged();

            }
            }
            ;
            }
            public interface ForumAdapterListener {
            void onDocumentSelected(String contact, String username, String created_at, String user_id, String flattitle, String message);
            }

          • Saket Mayank
  • Danijel Papiga

    What do in this project to display data from arraylist for example”articles” which then contains “title” “author” etc, Connection to the server I try is ok, but I get error json exception value. I’m new to this,and this list is kinda different, help if you can. Thanks.

  • Saket Mayank

    mAdapter = new ContactsAdapter(this, contactList, this);

    When I try to add this line inside my response call back it is generating error regarding the listener parameter .How to fix it?

    • Saket Mayank

      ok its done mAdapter = new ContactsAdapter(this, contactList, DiscussionForum.this);

  • Saket Mayank
  • Anselmo Alexandre Munguambe

    Nike tutorial man. Congrats.
    But am using fragment to fetch the data from the server. And I only use the activity to show the fragment.
    So as you may have guessed, my search is in the activity not in fragment.
    So how to I implement the search in Fragment?
    Thanks in advance

    • That,s My channel

      Use EditText instead.

      • Anselmo Alexandre Munguambe

        Can you be more especific?
        Can you provide tutorial or example of how to achieve the goal here?

  • Diana Nirmalasari

    if (row.getName().toLowerCase().contains(charString.toLowerCase()) || row.getPhone().contains(charSequence)) {
    filteredList.add(row);

    How to add more field to filter?

    • You just need to add fields to your POJO class and add the conditional statement here.

      • Diana Nirmalasari

        Sorry, I don’t understand….I am a beginner. Please give example suppose i will add ADDRESS field. Which script is changed?

        • If you are beginner. I suggest learn the basics first.

  • jeeban bagdi

    Really good and clearfull example.Bt i want to swipe from both side right to left and left to right with different functionality .please help me ?

    • There is a direction defined. Check and find the code.

  • Sagar Garg

    @ravi8x:disqus I am getting this error:
    java.lang.NullPointerException: Attempt to invoke virtual method ‘int android.view.View.getSystemUiVisibility()’ on a null object reference.
    Android studio is pointing to the below two lines for the error:
    whiteNotificationBar(recyclerView); &&
    int flags = view.getSystemUiVisibility();

  • SIDDHARTH KASUNDRA

    error: non-static method getFilter() cannot be referenced from a static context

  • Kevin Moses Kenap

    Hello sir, do you have tutorial show suggestion when user type keywords in search view in android studio? Thx

  • Mitesh Makwana

    is it possible to show two item on horizontal view and one on vertical view in recyclerview

  • Juliet Wanjohi

    Hi Ravi,

    Great tutorial! However, I have a recyclerview that is loading pages of records, so the search will only work once I’ve loaded all the pages. How do I make it work such that if I load the first page only, I can search for an attribute and it will return the result from the records loaded in the first page only?

  • Franco Berardi

    gracias amigo! funcionΓ³ perfecto, ya tenia creada la clase Myadapter, solo tuve que implementar la interfaz Filterable, tal cual tu ejemplo y salio andando de una. Thks, you saved me a lot of time!

  • Mian Abdul Mateen

    its giving exception while scrolling and search at same time

    java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{66836f position=125 id=-1, oldPos=-1, pLpos:-1 no parent}

  • Mitesh Makwana

    i am getting searchview ,text,icon, dark is it possible to change color of text ,icon color and searchview

    this is my primary color
    #232123
    #282628
    #448AFF

  • Vinod Kumar

    Hello Ravi, Thanks for post. I want to implement search feature in activity and my activity has two fragments, depends on user selected fragment search from activity should reflect in fragment recyclerview, how can I achieve this.