Implementing SearchView in action bar Implementing SearchView in action bar android android

Implementing SearchView in action bar


It took a while to put together a solution for this, but have found this is the easiest way to get it to work in the way that you describe. There could be better ways to do this, but since you haven't posted your activity code I will have to improvise and assume you have a list like this at the start of your activity:

private List<String> items = db.getItems();

ExampleActivity.java

private List<String> items;private Menu menu;@Override@TargetApi(Build.VERSION_CODES.HONEYCOMB)public boolean onCreateOptionsMenu(Menu menu) {    getMenuInflater().inflate(R.menu.example, menu);    this.menu = menu;    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {        SearchManager manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);        SearchView search = (SearchView) menu.findItem(R.id.search).getActionView();        search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));        search.setOnQueryTextListener(new OnQueryTextListener() {             @Override             public boolean onQueryTextChange(String query) {                loadHistory(query);                return true;             }         });    }    return true;}// History@TargetApi(Build.VERSION_CODES.HONEYCOMB)private void loadHistory(String query) {    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {        // Cursor        String[] columns = new String[] { "_id", "text" };        Object[] temp = new Object[] { 0, "default" };        MatrixCursor cursor = new MatrixCursor(columns);        for(int i = 0; i < items.size(); i++) {            temp[0] = i;            temp[1] = items.get(i);            cursor.addRow(temp);        }        // SearchView        SearchManager manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);        final SearchView search = (SearchView) menu.findItem(R.id.search).getActionView();        search.setSuggestionsAdapter(new ExampleAdapter(this, cursor, items));    }}

Now you need to create an adapter extended from CursorAdapter:

ExampleAdapter.java

public class ExampleAdapter extends CursorAdapter {    private List<String> items;    private TextView text;    public ExampleAdapter(Context context, Cursor cursor, List<String> items) {        super(context, cursor, false);        this.items = items;    }    @Override    public void bindView(View view, Context context, Cursor cursor) {        text.setText(items.get(cursor.getPosition()));    }    @Override    public View newView(Context context, Cursor cursor, ViewGroup parent) {        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);        View view = inflater.inflate(R.layout.item, parent, false);        text = (TextView) view.findViewById(R.id.text);        return view;    }}

A better way to do this is if your list data is from a database, you can pass the Cursor returned by database functions directly to ExampleAdapter and use the relevant column selector to display the column text in the TextView referenced in the adapter.

Please note: when you import CursorAdapter don't import the Android support version, import the standard android.widget.CursorAdapter instead.

The adapter will also require a custom layout:

res/layout/item.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent">    <TextView        android:id="@+id/item"        android:layout_width="wrap_content"        android:layout_height="wrap_content" /></RelativeLayout>

You can now customize list items by adding additional text or image views to the layout and populating them with data in the adapter.

This should be all, but if you haven't done this already you need a SearchView menu item:

res/menu/example.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">    <item        android:id="@+id/search"        android:title="@string/search"        android:showAsAction="ifRoom"        android:actionViewClass="android.widget.SearchView" /></menu>

Then create a searchable configuration:

res/xml/searchable.xml

<searchable xmlns:android="http://schemas.android.com/apk/res/android"    android:label="@string/search"    android:hint="@string/search" ></searchable>

Finally add this inside the relevant activity tag in the manifest file:

AndroidManifest.xml

<intent-filter>    <action android:name="android.intent.action.SEARCH" /></intent-filter><meta-data    android:name="android.app.default_searchable"    android:value="com.example.ExampleActivity" /><meta-data    android:name="android.app.searchable"    android:resource="@xml/searchable" />

Please note: The @string/search string used in the examples should be defined in values/strings.xml, also don't forget to update the reference to com.example for your project.


If anyone else is having a nullptr on the searchview variable, I found out that the item setup is a tiny bit different:

old:

android:showAsAction="ifRoom"android:actionViewClass="android.widget.SearchView"

new:

app:showAsAction="ifRoom|collapseActionView"app:actionViewClass="androidx.appcompat.widget.SearchView"

pre-android x:

app:showAsAction="ifRoom|collapseActionView"app:actionViewClass="android.support.v7.widget.SearchView"

For more information, it's updated documentation is located here.


SearchDialog or SearchWidget ?

When it comes to implement a search functionality there are two suggested approach by official Android Developer Documentation.
You can either use a SearchDialog or a SearchWidget.
I am going to explain the implementation of Search functionality using SearchWidget.

How to do it with Search widget ?

I will explain search functionality in a RecyclerView using SearchWidget. It's pretty straightforward.

Just follow these 5 Simple steps

1) Add searchView item in the menu

You can add SearchView can be added as actionView in menu using

app:useActionClass = "android.support.v7.widget.SearchView" .

<menu 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"   tools:context="rohksin.com.searchviewdemo.MainActivity">   <item       android:id="@+id/searchBar"       app:showAsAction="always"       app:actionViewClass="android.support.v7.widget.SearchView"   /></menu>

2) Set up SerchView Hint text, listener etc

You should initialize SearchView in the onCreateOptionsMenu(Menu menu) method.

  @Override  public boolean onCreateOptionsMenu(Menu menu) {     // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.menu_main, menu);        MenuItem searchItem = menu.findItem(R.id.searchBar);        SearchView searchView = (SearchView) searchItem.getActionView();        searchView.setQueryHint("Search People");        searchView.setOnQueryTextListener(this);        searchView.setIconified(false);        return true;   }

3) Implement SearchView.OnQueryTextListener in your Activity

OnQueryTextListener has two abstract methods

  1. onQueryTextSubmit(String query)
  2. onQueryTextChange(String newText

So your Activity skeleton would look like this

YourActivity extends AppCompatActivity implements SearchView.OnQueryTextListener{     public boolean onQueryTextSubmit(String query)     public boolean onQueryTextChange(String newText) }

4) Implement SearchView.OnQueryTextListener

You can provide the implementation for the abstract methods like this

public boolean onQueryTextSubmit(String query) {    // This method can be used when a query is submitted eg. creating search history using SQLite DB    Toast.makeText(this, "Query Inserted", Toast.LENGTH_SHORT).show();    return true;}@Overridepublic boolean onQueryTextChange(String newText) {    adapter.filter(newText);    return true;}

5) Write a filter method in your RecyclerView Adapter.

Most important part. You can write your own logic to perform search.
Here is mine. This snippet shows the list of Name which contains the text typed in the SearchView

public void filter(String queryText){    list.clear();    if(queryText.isEmpty())    {       list.addAll(copyList);    }    else    {       for(String name: copyList)       {           if(name.toLowerCase().contains(queryText.toLowerCase()))           {              list.add(name);           }       }    }   notifyDataSetChanged();}

Relevant link:

Full working code on SearchView with an SQLite database in this Music App