📜 ⬆️ ⬇️

Use Android Search Dialog. Simple application example

image

This article is intended for those who have already written their HelloWorld for Android and know what Activity and Intent are, as well as where the manifest is located and why we need layouts. Otherwise, you can familiarize yourself with this material, for example, on developer.android.com .

The article describes the creation of a simple application that uses the search implementation mechanism, based on the capabilities of the built-in framework. After reading, you can also customize your application so that it searches for data using the standard Android Search Dialog.

')

A bit of theory


Android Search Dialog (hereinafter referred to as the “search dialogue”) is controlled by the search framework. This means that the developer does not need to think about how to draw it or how to catch a search query. SearchManager will do this job for you.

So, when the user starts the search, SearchManager creates an Intent and sends it to the Activity, which is responsible for finding the data (the query itself is placed on the extras). That is, in fact, the application must have at least one Activity that receives search intent, performs a search, and provides the user with results. To implement will require the following:


Configuration file


Start by creating a configuration file, because this is the easiest part. Of course, you need to prepare in advance, create a new project, Activity (I use Activity “Main” and the name of the project “SearchExample”). All that is needed for configuration is to create a searchable.xml file in the res / xml / subdirectory of your project, with the following content.
<? 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 .

Only android: label is a mandatory attribute, and it must refer to a string that is the same as the application name. The second attribute, android: hint, is used to display a string in an empty dialog. For example, it can be “Search by Video” or “Search for Contacts”, etc. This attribute indicates what data is being searched. It is also important to know that the searchable element supports many other attributes, you can read more here .

Create an Activity


Minimally, all we need from the user interface. Activity is a list for displaying search results and a mechanism for invoking a search dialog. We will do this by adding only a text field and a button so that we can fill in the database ourselves. Looking ahead, I will say that the data will be stored in a SQLite database.

We describe the Activity interface as follows (the file is located in 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 .

As follows:

image

We also need the layout for the view of the list item, we describe it in the simplest way (the file is in 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 .


Also, don't forget about the resource file where our strings are stored (file in 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 .

I remind you that when a user performs a search, it is necessary for SearchManager to send an Intent along with a search query to our Activity. In order for SearchManager to know exactly where to send it an Intent, you need to announce this in the manifest. So, go to AndroidManifest.xml, and change it so that the Activity can accept Intents like Search. In addition, apply our searchable.xml configuration file. So, the manifest will look something like this:
<? 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" />

</ manifest >


* This source code was highlighted with Source Code Highlighter .

Now, you can already check if you did everything right. You can call the dialogue on the emulator, for example, by clicking the search button. Well, or if you check on the device, then holding down the "Menu". It should look like this:

image

Performing a search


After we announced our Activity and made the necessary changes to AndroidManifest.xml, we can consider the search itself. It includes three stages:

Receive request

Since the SearchManager sends an Search type Search Intent to our Activity, all that needs to be done is to check for an Intent of this type when the Activity starts. Then, if we get the desired Intent, we can extract extras from it and perform a search.

Search data

Since the type of data storage structure for different applications may vary, the methods for them are different. In our case, the easiest way is to perform a query on the SQLite database table with the LIKE query. Of course, it is better to use FTS3, it is much faster; you can read more about FTS3 on SQLite.org . Ideally, you should also always expect that the search can take a long time, so you can create some ProgressDialog so that the interface does not hang and that the user knows that the application is working.

Output Results

In general, the output of the results is a UI problem, but since we use ListView, for us the problem is solved by simply updating the adapter.

Source


Finally, I provide the full source code for the two classes with comments. The first is Main, the heir to ListActivity, it is used to populate the database and display the results. The second class is RecordsDbHelper, it implements an interface for interacting with the database. The most important methods are adding entries and finding matches using the LIKE query.

Main.java file
package com.example.search;

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 .


RecordsDbHelper.java file
package com.example.search;

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) {

db.execSQL(DATABASE_CREATE);
}

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

Conclusion

The article was written using developer.android.com documentation.
The whole project can be taken at code.google.com .

Source: https://habr.com/ru/post/111475/


All Articles