Browse through more Android tutorials. If you'd like to see a tutorial on any particular topic, do leave a comment in the wishlist page. We frequently post new tutorials along with app releases. You may subscribe to our newsletter to get all updates in your inbox.
Now you can get the latest Java source bundled with each app update. Install the app from Google Play and go to Settings > Extras.

«  Create a notepad/to-do list app Create Flappy Bird in Android  »

Create a currency converter application using Yahoo! API

DownloadDownload

Keywords: ConnectivityManager HttpGet XmlPullParser SAXParser SimpleCursorAdapter SQLiteDatabase ContentProvider SQLiteQueryBuilder BroadcastReceiver IntentService AChartEngine Search Dialog Animation TableLayout

Contents

6 « Prev Page

15. The Search Dialog

The Search Dialog is a UI component provided by Android that allows you to surface your application's content in a standard manner. When activated by pressing harware search key or programmatically through onSearchRequested(), it appears at the top of the activity window.
Implementing search involves the following:
  • A searchable configuration XML file
  • A searchable activity

To enable search dialog for a given activity you need to add a meta-data tag to the activity node in the manifest and in the value attribute specify the searchable activity. We have already done this for MainActivity in the previous section.
	<meta-data android:name="android.app.default_searchable"  
		android:value=".SearchableActivity" />
					
First, create a configuration file searchable.xml in res/xml directory.
	<?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"
		android:searchSuggestAuthority="com.appsrox.forexwiz.provider"
		android:searchSuggestIntentAction="android.intent.action.VIEW"
		android:searchSuggestIntentData="content://com.appsrox.forexwiz.provider/symbol">
	</searchable>
					
Although android:label attribute is the only required attribute and it's recommended to specify android:hint attribute, we specify other attributes since we also implement custom suggestions with search.
Next, create SearchableActivity to display the search results.
	public class SearchableActivity extends ListActivity {
		private SQLiteDatabase db;

		@Override
		protected void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
			db = ForexWiz.db;
			handleIntent();
		}

		@Override
		protected void onNewIntent(Intent intent) {
			setIntent(intent);
			handleIntent();
		}
		
		private void handleIntent() {
			Intent intent = getIntent();
			if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
				String searchQuery = intent.getStringExtra(SearchManager.QUERY);
				doSearch(searchQuery);
				
			} else if (Intent.ACTION_VIEW.equals(intent.getAction())) {
				Uri detailUri = intent.getData();
				long id = Long.parseLong(detailUri.getLastPathSegment());
				addSymbol(id);
				finish();
			}
		}
		
		private void doSearch(String query) {
			Cursor c = db.rawQuery(&quot;SELECT _id, name, country FROM symbol WHERE isTracked = 1&quot;, 
									null);
			startManagingCursor(c);
			SimpleCursorAdapter adapter = (SimpleCursorAdapter) getListAdapter();
			if (adapter == null) {
				adapter = new SimpleCursorAdapter(
						this, 
						android.R.layout.simple_list_item_2, 
						c, 
						new String[]{"name", "country"}, 
						new int[]{android.R.id.text1, android.R.id.text2});
				setListAdapter(adapter);
				
			} else {
				(adapter).changeCursor(c);
			}
		}

		@Override
		protected void onListItemClick(ListView l, View v, int position, long id) {
			addSymbol(id);
			finish();
		}
		
		private void addSymbol(long id) {
			Symbol symbol = new Symbol(id);
			symbol.setTracked(true);
			symbol.update(db);
		}
	}				
					
When search is executed Android launches this activity with action set to Intent.ACTION_SEARCH and passes the search query as a string extra. The doSearch() method is invoked which creates an adapter and the result is displayed in the list view. Search Results screen The SearchableActivity is also launched when user clicks on a suggestion and the action is set to Intent.ACTION_VIEW since we have specified this using android:searchSuggestIntentAction attribute in searchable.xml. In this case we don't show the list view instead we add the symbol and then finish the activity.
Declare the activity in the manifest as follows.
	<activity 
		android:name=".SearchableActivity"
		android:label="Currency Search"
		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>
					
Notice that we have set android:launchMode to singleTop since we only want a single instance of the search activity. So we override onNewIntent() method in SearchableActivity to set the new intent as default.
Finally, we need to implement a provider for the search suggestions. We have already declared the authority using android:searchSuggestAuthority in searchable.xml file. The authority must match with a provider declared in the manifest.
	<provider android:name=".SuggestionProvider" 
				android:authorities="com.appsrox.forexwiz.provider"></provider>
					
We will next implement the ContentProvider for search suggestions.
	public class SuggestionProvider extends ContentProvider {
		public static final Uri CONTENT_URI = Uri.parse("content://com.appsrox.forexwiz.provider/symbol");
		
		private static final int ALL = 1;
		private static final int ROW_ID = 2;
		private static final int SEARCH = 3;
		
		private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
		static {
			matcher.addURI(CONTENT_URI.getAuthority(), "symbol", ALL);
			matcher.addURI(CONTENT_URI.getAuthority(), "symbol/#", ROW_ID);
			matcher.addURI(CONTENT_URI.getAuthority(), SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH);
			matcher.addURI(CONTENT_URI.getAuthority(), SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH);
		}
		
		private SQLiteDatabase db;

		@Override
		public boolean onCreate() {
			DbHelper dbHelper = new DbHelper(getContext());
			db = dbHelper.getReadableDatabase();
			return true;
		}
		
		private static final HashMap<String, String> PROJECTION_MAP = new HashMap<String, String>();
		static {
			PROJECTION_MAP.put("_id", "_id");
			PROJECTION_MAP.put(SearchManager.SUGGEST_COLUMN_TEXT_1, 
								"code AS " + SearchManager.SUGGEST_COLUMN_TEXT_1);
			PROJECTION_MAP.put(SearchManager.SUGGEST_COLUMN_TEXT_2, 
								"country || ' ' || name AS " + SearchManager.SUGGEST_COLUMN_TEXT_2);
			PROJECTION_MAP.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, 
								"_id AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);
		}

		@Override
		public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
			SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
			builder.setTables(Symbol.TABLE_NAME);
			
			switch(matcher.match(uri)) {
			case SEARCH:
				String query = uri.getLastPathSegment();
				builder.appendWhere("isTracked = 0 AND (");
				builder.appendWhere("name LIKE '" + query + "%' OR ");
				builder.appendWhere("country LIKE '" + query + "%' OR ");
				builder.appendWhere("code LIKE '" + query + "%')");
				builder.setProjectionMap(PROJECTION_MAP);
				break;
			}
			return builder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
		}

		@Override
		public String getType(Uri uri) {
			return null;
		}
		@Override
		public Uri insert(Uri uri, ContentValues values) {
			throw new UnsupportedOperationException();
		}
		@Override
		public int delete(Uri uri, String selection, String[] selectionArgs) {
			throw new UnsupportedOperationException();
		}
		@Override
		public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
			throw new UnsupportedOperationException();
		}
	}
					
Search suggestions are displayed below the search dialog as user types in the search box. Custom Search Suggestions Android expects from the content provider to return few standard columns so that it can display the suggestions. That is why we create a projection map from the existing table columns and use SQLiteQueryBuilder to construct the query.
We'll next develop the details screen and see how to plot historical exchange rates using AChartEngine library.
Share the love:  

Next Page » 6

App Gen
App Name:
Project Name:
Package:
Screens:
Splash
Login
Help
Main
List  Grid  Pager
Detail
Settings
Options:
Action Bar
Navigation Drawer
Dummy Data
Generate
Free Apps