In this article, we will add search functionality to the database list application we developed in our previous article.
You can add the search interface either using the search dialog or the search widget.
A search dialog shows up at the top of the activity window whereas a search widget can be inserted anywhere in the layout.
The search widget is an instance of SearchView
and is is available only in Android 3.0 (API Level 11) and higher.
In this article, we will be using search widget as the search interface.
Search Components
The search components and the flow are mostly same for both search dialog and search widget.
When the user executes a search from the search dialog or a search widget, the system creates an Intent
and stores the user query in it. The system then starts the search activity we have declared in androidManifest.xml
. In the search activity, we can retrieve the query from the Intent
object, perform the search and return the search results.
To implement search framework, we need the following components:
- A searchable configuration – An XML file that configures some settings for the search dialog or widget.
- A searchable activity – This can be a
ListActivity
that receives the search query from theIntent
, searches your data, and then sets the search results to the list adapter. - A Search dialog or Search View Widget – Search dialog is hidden initially but appears at the top of the screen when you call
onSearchRequested()
. If you are using search widget, you may want to include it as an action bar item.
Add SearchView Widget to ActionBar
Add SearchView widget to the menu. actionViewClass
attribute must be set to android.widget.SearchView
. We have set showAsAction
to ifRoom|collapseActionView
which means the search view widget will be added to the action bar if there is enough room and it will be collapsed into a button The collapsed search button may appear in the overflow or in the action bar itself if there is enough space. You will the search action bar moment the user selects the action button.
main.xml:
<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="com.javarticles.android.SearchableActivity" > <item android:id="@+id/search" android:actionViewClass="android.widget.SearchView" android:icon="@drawable/ic_search" android:showAsAction="ifRoom|collapseActionView" android:title="@string/search_label"/> </menu>
Configuring the search widget
Create searchable configuration XML file called searchable.xml
in dir res/xml/
. Android uses this XML file to create SearchableInfo
which will later use to configure the search view.
Below is a simple search configuration XML, <searchable>
is the root element. android:label
is a mandatory element and must contain the application’s label. android:hint
will be used to add a hint label to the search view, which remains visible till users enters a query.
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/search_hint"> </searchable>
We can configure the search widget in onCreateOptionsMenu()
callback.
- First inflate the menu as search item is added to menu.
getMenuInflater().inflate(R.menu.main, menu);
- You can get a reference to the SearchableInfo by calling getSearchableInfo() on SearchManager.
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); SearchableInfo searchableInfo = searchManager.getSearchableInfo(getComponentName());
SearchableInfo
object represents your searchable configuration. This needs to be set to theSearchView
widget.searchView.setSearchableInfo(searchableInfo);
LanguageListActivity:
package com.javarticles.android; import android.app.ListActivity; import android.app.LoaderManager.LoaderCallbacks; import android.app.SearchManager; import android.content.Context; import android.content.CursorLoader; import android.content.Loader; import android.database.Cursor; import android.os.Bundle; import android.view.Menu; import android.widget.CursorAdapter; import android.widget.SearchView; import android.widget.SimpleCursorAdapter; import com.javarticles.android.database.DatabaseConstants; public class LanguageListActivity extends ListActivity implements LoaderCallbacks { private static final int LOADER_ID = 42; private CursorAdapter _adapter; public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.container_list); _adapter = new SimpleCursorAdapter(this, R.layout.container_list_item_view, null, new String[] { DatabaseConstants.COL_LANG_NAME }, new int[] { R.id.list_item }); setListAdapter(_adapter); getLoaderManager().initLoader(LOADER_ID, null, this); } @Override public Loader onCreateLoader(int id, Bundle args) { if (id != LOADER_ID) { return null; } return new CursorLoader(LanguageListActivity.this, LanguageContentProvider.CONTENT_URI, new String[] { DatabaseConstants.COL_LANG_ID, DatabaseConstants.COL_LANG_NAME }, null, null, null); } @Override public void onLoadFinished(Loader loader, Cursor data) { _adapter.swapCursor(data); } @Override public void onLoaderReset(Loader loader) { _adapter.swapCursor(null); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); SearchView searchView = (SearchView) menu.findItem(R.id.search).getActionView(); searchView.setSearchableInfo( searchManager.getSearchableInfo(getComponentName())); return true; } }
SearchableActivity
our activity that performs searches based on a query string and presents the search results. When the user enters a query and executes the search, the system starts your searchable activity and delivers the search query in an Intent
with android.intent.action.SEARCH
as the action key. You can access this action using constant Intent.ACTION_SEARCH
.
private void handleIntent(Intent intent) { if (Intent.ACTION_SEARCH.equals(intent.getAction())) { String query = intent.getStringExtra(SearchManager.QUERY); doMySearch(query); } }
The searchable activity needs to extract the query from the intent’s QUERY
extra, then searches your data and presents the results. Since our data is in database, we will use a database query to create Cursor
and then create a SimpleCursorAdapter
adapter to set the list model.
private void doMySearch(String query) { SQLiteHelper sqLiteHelper = ((MyApplication)getApplication()).getDbHelper(); Cursor cursor = sqLiteHelper.getReadableDatabase().rawQuery("SELECT " + DatabaseConstants.COL_LANG_ID + ", " + DatabaseConstants.COL_LANG_NAME + " FROM " + DatabaseConstants.TABLE_LANG + " WHERE upper(" + DatabaseConstants.COL_LANG_NAME + ") like '%" + query.toUpperCase() + "%'", null); setListAdapter(new SimpleCursorAdapter(this, R.layout.container_list_item_view, cursor, new String[] {DatabaseConstants.COL_LANG_NAME }, new int[]{R.id.list_item})); }
SearchableActivity:
package com.javarticles.android; import android.app.ListActivity; import android.app.SearchManager; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.os.Bundle; import android.view.Menu; import android.widget.SearchView; import android.widget.SimpleCursorAdapter; import com.javarticles.android.database.DatabaseConstants; public class SearchableActivity extends ListActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.container_list); handleIntent(getIntent()); } @Override protected void onNewIntent(Intent intent) { setIntent(intent); handleIntent(intent); } private void handleIntent(Intent intent) { if (Intent.ACTION_SEARCH.equals(intent.getAction())) { String query = intent.getStringExtra(SearchManager.QUERY); doMySearch(query); } } private void doMySearch(String query) { SQLiteHelper sqLiteHelper = ((MyApplication)getApplication()).getDbHelper(); Cursor cursor = sqLiteHelper.getReadableDatabase().rawQuery("SELECT " + DatabaseConstants.COL_LANG_ID + ", " + DatabaseConstants.COL_LANG_NAME + " FROM " + DatabaseConstants.TABLE_LANG + " WHERE upper(" + DatabaseConstants.COL_LANG_NAME + ") like '%" + query.toUpperCase() + "%'", null); setListAdapter(new SimpleCursorAdapter(this, R.layout.container_list_item_view, cursor, new String[] {DatabaseConstants.COL_LANG_NAME }, new int[]{R.id.list_item})); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); SearchView searchView = (SearchView) menu.findItem(R.id.search).getActionView(); searchView.setSearchableInfo( searchManager.getSearchableInfo(getComponentName())); return true; } }
Declare search activity and intent in android Manifest
- You need to declare the search activity.
- You also need to declare the intent to accept the ACTION_SEARCH action using
<intent-filter>
element. - You will also have to specify the searchable configuration XML resource used in a <meta-data> element.
- Finally, we need to specify
<meta-data> element
withandroid:name
asandroid.app.default_searchable
and value asSearchableActivity
Specify the searchable configuration to use, in a element.
androidManifest.xml:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.javarticles.android" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:maxSdkVersion="22" android:minSdkVersion="14" android:targetSdkVersion="22" /> <application android:name="com.javarticles.android.MyApplication" android:allowBackup="true" android:icon="@drawable/ic_launcher_sandbox" android:label="@string/app_name" > <activity android:name="com.javarticles.android.LanguageListActivity" > <meta-data android:name="android.app.default_searchable" android:value=".SearchableActivity" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SearchableActivity" 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> <provider android:name=".LanguageContentProvider" android:authorities="com.javarticles.android.provider.LanguageContentProvider" android:exported="false" /> </application> </manifest>
Run the Android Search Example
Download the source code
This was an example about adding search functionality to the database list application.