Adding Search Functionality to Your Android Application Activity with SearchView and Search Dialog

If you’re building an android application, then most likely you’ll need to implement a search in it to let the user search through a set of data that could be emails, messages, chats, photos, files, etc. Android provides us with a search widget called SearchView that provides a user interface for the user to enter a search query and submit the request. The preferred way to use this widget to provide search in our application is to use it in the action bar.

There’s another way to implement a search interface in Android which is by using the search dialog which we’ll discuss later in this post. Although note that using the SearchView widget in the action bar as an item is the preferred way to provide search in your application since Android 3.0.

What's the one thing every developer wants? More screens! Enhance your coding experience with an external monitor to increase screen real estate.

Adding Search View to Action Bar

Adding the search view to the action bar is really simple. We just need to add a menu item in our XML menu resource.

<item android:id="@+id/search"
        android:title="Search"
        android:icon="@drawable/ic_search"
        android:showAsAction="collapseActionView|ifRoom"
        android:actionViewClass="android.widget.SearchView" />

An action view is a widget that replaces an action button to provide fast access to rich actions like search without switching to other activities or fragments and without replacing the action bar entirely. Declaring an action view is done with the actionLayout attribute that specifies a layout resource or the actionViewClass attribute that specifies a widget to use. In this case actionViewClass is used which is set to android.widget.SearchView which embeds the SearchView in our action bar.

Also notice the collapseActionView value for the showAsAction attribute. That value means that the action view will be collapsed into an action button. On collapsing, the action might be placed into the action bar or the overflow menu, depending upon the space available.

Searchable Configuration

To configure certain UI aspects of the search widget, deliver search queries to an activity and define how certain features should behave, we must provide a search configuration in the form of an XML file. This configuration file must be saved in the res/xml/ project directory (and is traditionally named searchable.xml).

<?xml version="1.0" encoding="utf-8"?>

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

The android:label attribute is the only required attribute that should have the same value as the android:label attribute of the or element in our AndroidManifest.xml.

Although not strictly required, but the android:hint attribute’s value hints the user as to what he can expect to search for in the search widget (or dialog) before writing his search query. It basically serves as a placeholder until something is typed into the search box.

Note: In order for the hint to actually show up in the UI, the searchable configuration and searchable activity must be properly setup and tied to each other in the manifest file. I’ll talk about searchable activity and what all needs to be done in the manifest file in a bit. Also the value of android:hint must be a string resource.

The searchable configuration can be used to add other features like search suggestions, voice search, etc. For further information about what all attributes the element can accept, you should go through the documentation.

Searchable Activity

A Searchable activity is one that takes the query string that the user looked up for and performs the search to show the results. When the user performs a search in the dialog or widget, android will start the searchable activity and pass it the search query in an Intent with the ACTION_SEARCH action. The search query is obtained from the intent’s SearchManager.QUERY extra data key.

Let’s create a new searchable activiy called SearchResultsActivity.java that’ll look like this:

public class SearchResultsActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        handleIntent(getIntent());
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        
        handleIntent(intent);
    }

    private void handleIntent(Intent intent) {

        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            String query = intent.getStringExtra(SearchManager.QUERY);

            showResults(query);
        }
    }

    private void showResults(String query) {
        // Query your data set and show results
        // ...
    }
}

getStringExtra is how we retrieve extended data from the intent.

Once you get the query string in the `showResults()` method, you should use that to query your data set which could be a database, online remote service or some other form of data source and show the result in an appropriate format like a list.

Tying the Searchable Configuration and Activity

Now that we’re done with creating our searchable configuration file and the Activity class, we have to perform certain steps in order to tie them so that they can work in conjunction.

First, in the android manifest file, we’ll declare our searchable activity to accept the ACTION_SEARCH intent, using an element. After that we’ll have to also specify the searchable configuration file to use using element. So this is how it’ll look like:

<activity
    android:name=".SearchResultsActivity"
    android:label="@string/title_activity_search_results">

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

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

</activity>

The android:name attribute of the element must have the value android.app.searchable and the android:resource attribute refers to the file at res/xml/searchable.xml.

Now if you want to have a separate Activity to show the search dialog or widget that’ll send the query string to SearchResultsActivity activity then we’ll need to put a element for that activity too in the manifest file to declare that SearchResultsActivity is the searchable activity for the other activity. Let’s call the other activity ContactsActivity, then this is how it’s going to be:

<activity
    android:name=".ContactsActivity"
    android:label="@string/title_activity_contacts">

    <meta-data
        android:name="android.app.default_searchable"
        android:value=".SearchResultsActivity" />
</activity>

Notice this time the value for android:name is android.app.default_searchable which defines which activity to use as the searchable activity through the android:value attribute’s value.

Let’s say we have a single activity to handle both, the search box interface as well as the results interface, then what happens is that everytime there’s a new intent (a new search is executed), a new instance of the class is created to respond to that intent. Hence, certain things get messed up, for example the back button. This happens because the default android:launchMode for the activity is `standard`. We can fix this by setting it to singleTop.

<activity
    android:name=".SearchResultsActivity"
    android:label="@string/title_activity_search_results"
    android:launchMode="singleTop">

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

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

</activity>

There’s just one change in the code, which is the declaration of the launch mode. When it is set to singleTop, then the existing instance of the activity class keeps on receiving the new intent. This has to be handled in the onNewIntent() method of the Activity (which we already defined above). So now every time a the user submits a query, the onNewIntent() method is called that can call the same method shared with onCreate() to display result.

Associating Searchable Configuration with SearchView

Finally, to bind the searchable configuration to the SearchView and make sure everything works properly, we need to write a small piece of code in the onCreateOptionsMenu() method of the activity that has the search widget.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.contacts, menu);

    SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView searchView = (SearchView) menu.findItem(R.id.search).getActionView();
    searchView.setSearchableInfo( searchManager.getSearchableInfo(getComponentName()) );

    return true;
}

The call to getSearchableInfo() on the SearchManager returns a SearchableInfo object that represents the searchable configuration as it is created from the configuration XML file. Passing the object to setSearchableInfo() associates it with the SearchView which can now start an activity with the ACTION_SEARCH intent when a user executes a search.

Using the Search Dialog

The search dialog appears as a floating box at the top of the screen/activity with the application icon on the left. It is completely controlled by the system. Activating the search dialog and showing it up is very simple, you just need to call the onSearchRequested() method on the Activity. So if I have a control (action button) in the menu then I can add this piece of code in onOptionsItemSelected():

if (id == R.id.search) {
    onSearchRequested();
    return true;
}

You could also have a button in the UI layout triggering the same function call to invoke the search dialog.

The process of setting up the searchable configuration and activity, all remains the same as the SearchView for a search dialog.

Unless overridden, calling onSearchRequested() is same as calling startSearch(null, false, null, false). Sometimes you might want to pass on additional specific data alongside the search query. You can do that by overriding the onSearchRequested() method like this:

@Override
public boolean onSearchRequested() {
    Bundle appData = new Bundle();
    appData.putString("hello", "world");
    startSearch(null, false, appData, false);
    return true;
}

And then fetch the data in your searchable activity like this (when the user submits a query):

Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
if (appData != null) {
    String hello = appData.getString("hello");
}

Wrapping Up

So as you can see, android makes it really easy to integrate search to your apps quickly. Just remember that if you’re developing for Android 3.0 and above, then you’d most likely want to use the search widget (SearchView) and not the dialog.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Author: Rishabh

Rishabh is a full stack web and mobile developer from India. Follow me on Twitter.

5 thoughts on “Adding Search Functionality to Your Android Application Activity with SearchView and Search Dialog”

  1. hey, i tried this code. when i press the options button , the search and settings option come up, but when i click on the search option, nothing happens.

  2. photos, pictures, images?

    A simple image says me whether the functionality you are providing is the same i am looking for , so i dont have to waste my time.

  3. good example , but you used bot add one more meta-data tag inside application tag and outside activity tag which look like

    without this SearchResultsActivity will not responds.

Leave a Reply

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