- Android Search Widget Example
- Search Components
- Add SearchView Widget to ActionBar
- Configuring the search widget
- Declare search activity and intent in android Manifest
- Использование Android Search Dialog. Пример простого приложения
- Немного теории
- Конфигурационный файл
- Создаем Activity
- Выполнение поиска
- Исходный код
Android Search Widget Example
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 the Intent , 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.
Android Search Components
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.
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, 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.
We can configure the search widget in onCreateOptionsMenu() callback.
- First inflate the menu as search item is added to menu.
- You can get a reference to the SearchableInfo by calling getSearchableInfo() on SearchManager.
- SearchableInfo object represents your searchable configuration. This needs to be set to the SearchView widget.
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 .
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.
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 element.
- You will also have to specify the searchable configuration XML resource used in a element.
- Finally, we need to specify element with android:name as android.app.default_searchable and value as SearchableActivity
Specify the searchable configuration to use, in a element.
Источник
Использование Android Search Dialog. Пример простого приложения
Данная статья предназначена для тех, кто уже написал свой HelloWorld для Android и знает, что такое Activity и Intent, а так же где находится манифест, и зачем нужны layout’ы. В противном случае, можно ознакомиться с этим материалом, например, на developer.android.com.
В статье описывается создание несложного приложения, которое использует механизм реализации поиска, основанный на возможностях встроенного фреймворка. После прочтения вы также сможете настроить свое приложение таким образом, чтобы оно осуществляло поиск по данным, используя стандартный Android Search Dialog.
Немного теории
Android Search Dialog (далее — «диалог поиска») управляется с помощью поискового фреймворка. Это означает, что разработчику не нужно задумываться над тем как его нарисовать или как отловить поисковый запрос. За вас эту работу сделает SearchManager.
Итак, когда пользователь запускает поиск, SearchManager создает Intent, и направляет его к Activity, которое отвечает за поиск данных (при этом сам запрос помещается в экстры). То есть по сути в приложении должно быть хотя бы одно Activity, которое получает поисковые Intent’ы, выполняет поиск, и предоставляет пользователю результаты. Для реализации потребуется следующее:
- Конфигурационный xml файл (в нем содержится информация о диалоге)
- Activity, которое будет получать поисковые запросы, выполнять поиск и выводить результаты на экран
- Механизм вызова поискового диалога (так как не все устройства с Android на борту имеют на корпусе кнопку поиска)
Конфигурационный файл
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 >
* This source code was highlighted with Source Code Highlighter .
Обязательным атрибутом является только android:label, причем он должен ссылаться на строку, которая является такой же, что и название приложения. Второй атрибут, android:hint используется для отображения строки в пустом диалоге. Например, это может быть «Поиск по Видео» или «Поиск контактов» и т.п. Этот атрибут указывает на то, по каким данным осуществляется поиск. Также важно знать, что элемент searchable поддерживает множество других атрибутов, подробнее можно прочесть Здесь.
Создаем Activity
Минимально, всё что нам нужно от пользовательского интерфейса Activity — это список для вывода результатов поиска и механизм вызова поискового диалога. Так и сделаем, добавив только поле для ввода текста и кнопку, чтобы мы сами могли заполнять базу. Забегая вперед, скажу, что данные будем хранить в БД SQLite.
Опишем интерфейс Activity следующим образом (файл находится в res/layout/main.xml).
xml version =»1.0″ encoding =»utf-8″ ? >
LinearLayout xmlns:android =»http://schemas.android.com/apk/res/android»
android:orientation =»vertical»
android:layout_width =»fill_parent»
android:layout_height =»fill_parent» >
LinearLayout
android:orientation =»horizontal»
android:layout_width =»fill_parent»
android:layout_height =»wrap_content»
android:gravity =»top» >
EditText
android:id =»@+id/text»
android:layout_width =»wrap_content»
android:layout_height =»wrap_content»
android:hint =»@string/text»
android:layout_weight =»100.0″/>
Button
android:id =»@+id/add»
android:layout_width =»wrap_content»
android:layout_height =»wrap_content»
android:text =»@string/add»/>
LinearLayout >
ListView
android:id =»@android:id/list»
android:layout_width =»fill_parent»
android:layout_height =»wrap_content»/>
TextView
android:layout_gravity =»left»
android:id =»@android:id/empty»
android:layout_width =»fill_parent»
android:layout_height =»fill_parent»
android:text =»@string/no_records»/>
LinearLayout >
* This source code was highlighted with Source Code Highlighter .
Выглядит следующим образом:
Также нам понадобится layout для вида элемента списка, опишем его простейшим образом (файл находится в res/layout/record.xml)
xml version =»1.0″ encoding =»utf-8″ ? >
TextView
android:id =»@+id/text1″
xmlns:android =»http://schemas.android.com/apk/res/android»
android:layout_width =»wrap_content»
android:layout_height =»wrap_content»
/>
* This source code was highlighted with Source Code Highlighter .
Также, не забываем про файл ресурсов, где хранятся наши строки (файл в res/values/strings.xml)
xml version =»1.0″ encoding =»utf-8″ ? >
resources >
string name =»app_name» > SearchExample string >
string name =»add» > Add string >
string name =»text» > Enter text string >
string name =»no_records» > There are no records in the table string >
string name =»search_hint» > Search the records string >
string name =»search» > Search string >
resources >
* This source code was highlighted with Source Code Highlighter .
xml version =»1.0″ encoding =»utf-8″ ? >
manifest xmlns:android =»http://schemas.android.com/apk/res/android»
package =»com.example.search»
android:versionCode =»1″
android:versionName =»1.0″ >
application android:icon =»@drawable/icon» android:label =»@string/app_name» >
activity android:name =».Main»
android:label =»@string/app_name» >
intent-filter >
action android:name =»android.intent.action.MAIN»/>
category android:name =»android.intent.category.LAUNCHER»/>
intent-filter >
intent-filter >
action android:name =»android.intent.action.SEARCH»/>
intent-filter >
meta-data
android:name =»android.app.searchable»
android:resource =»@xml/searchable»
/>
activity >
application >
uses-sdk android:minSdkVersion =»5″/>
* This source code was highlighted with Source Code Highlighter .
Сейчас, вы уже можете проверить, все ли вы сделали правильно. Вызвать диалог на эмуляторе можно, например, нажав кнопку поиска. Ну или если вы проверяете на девайсе, то зажав «Меню». Выглядеть должно примерно так:
Выполнение поиска
Получение запроса
Так как SearchManager посылает Intent типа Search нашему Activity, то всё что нужно сделать это проверить на Intent этого типа при старте Activity. Тогда, если мы получаем нужный Intent, то можно извлекать из него экстру и выполнять поиск.
Поиск данных
Так как тип структуры хранения данных для разных приложений может различаться, то и методы для них свои. В нашем случае, проще всего выполнить запрос по таблице БД SQLite запросом LIKE. Конечно, лучше использовать FTS3, он значительно быстрее, подробнее о FTS3 можно прочесть на сайте SQLite.org. В идеале, также нужно всегда рассчитывать, что поиск может занять продолжительное время, поэтому можно создать какой-нибудь ProgressDialog, чтобы у нас не завис интерфейс, и чтобы пользователь знал, что приложение работает.
Вывод результатов
Вообще вывод результатов — это проблема UI, но так как мы используем ListView, то для нас проблема решается простым обновлением адаптера.
Исходный код
Наконец, привожу полный исходный код двух классов с комментариями. Первый — Main, наследник ListActivity, он используется для наполнения БД и вывода результатов. Второй класс — RecordsDbHelper, он реализует интерфейс для взаимодействия с БД. Самые важные методы — добавление записей и поиск совпадений, с помощью запроса LIKE.
import android.app.ListActivity;
import android.app.SearchManager;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SimpleCursorAdapter;
public class Main extends ListActivity <
private EditText text;
private Button add;
private RecordsDbHelper mDbHelper;
@Override
public void onCreate(Bundle savedInstanceState) <
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Создаем экземпляр БД
mDbHelper = new RecordsDbHelper( this );
//Открываем БД для записи
mDbHelper.open();
//Получаем Intent
Intent intent = getIntent();
//Проверяем тип Intent
if (Intent.ACTION_SEARCH.equals(intent.getAction())) <
//Берем строку запроса из экстры
String query = intent.getStringExtra(SearchManager.QUERY);
//Выполняем поиск
showResults(query);
>
add = (Button) findViewById(R.id.add);
text = (EditText) findViewById(R.id.text);
add.setOnClickListener( new View.OnClickListener() <
public void onClick(View view) <
String data = text.getText().toString();
if (!data.equals( «» )) <
saveTask(data);
text.setText( «» );
>
>
>);
>
private void saveTask( String data) <
mDbHelper.createRecord(data);
>
private void showResults( String query) <
//Ищем совпадения
Cursor cursor = mDbHelper.fetchRecordsByQuery(query);
startManagingCursor(cursor);
String [] from = new String [] < RecordsDbHelper.KEY_DATA >;
int [] to = new int [] < R.id.text1 >;
SimpleCursorAdapter records = new SimpleCursorAdapter( this ,
R.layout.record, cursor, from , to);
//Обновляем адаптер
setListAdapter(records);
>
//Создаем меню для вызова поиска (интерфейс в res/menu/main_menu.xml)
public boolean onCreateOptionsMenu(Menu menu) <
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true ;
>
public boolean onOptionsItemSelected(MenuItem item) <
switch (item.getItemId()) <
case R.id.search_record:
onSearchRequested();
return true ;
default :
return super.onOptionsItemSelected(item);
>
>
>
* This source code was highlighted with Source Code Highlighter .
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class RecordsDbHelper <
public static final String KEY_DATA = «data» ;
public static final String KEY_ROWID = «_id» ;
private static final String TAG = «RecordsDbHelper» ;
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
private static final String DATABASE_CREATE = «CREATE TABLE records(_id INTEGER PRIMARY KEY AUTOINCREMENT, »
+ «data TEXT NOT NULL);» ;
private static final String DATABASE_NAME = «data» ;
private static final String DATABASE_TABLE = «records» ;
private static final int DATABASE_VERSION = 1;
private final Context mCtx;
private static class DatabaseHelper extends SQLiteOpenHelper <
DatabaseHelper(Context context) <
super(context, DATABASE_NAME, null , DATABASE_VERSION);
>
@Override
public void onCreate(SQLiteDatabase db) <
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) <
Log.w(TAG, «Upgrading database from version » + oldVersion + » to »
+ newVersion + «, which will destroy all old data» );
db.execSQL( «DROP TABLE IF EXISTS tasks» );
onCreate(db);
>
>
public RecordsDbHelper(Context ctx) <
this .mCtx = ctx;
>
public RecordsDbHelper open() throws SQLException <
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this ;
>
public void close() <
mDbHelper.close();
>
//Добавляем запись в таблицу
public long createRecord( String data) <
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_DATA, data);
return mDb.insert(DATABASE_TABLE, null , initialValues);
>
//Поиск запросом LIKE
public Cursor fetchRecordsByQuery( String query) <
return mDb.query( true , DATABASE_TABLE, new String [] < KEY_ROWID,
KEY_DATA >, KEY_DATA + » LIKE» + «‘%» + query + «%'» , null ,
null , null , null , null );
>
>
* This source code was highlighted with Source Code Highlighter .
Источник