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
<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.