Android SearchView using SQLite fts3 module example

How to use SearchView along with SQLite fts3 module that implements SearchView.OnQueryTextListener, SearchView.OnCloseListener in an Android activity

When you're ready to add search functionality to your application, Android helps you implement the user interface with either a search dialog that appears at the top of the activity window or a search widget that you can insert in your layout. Both the search dialog and the widget can deliver the user's search query to a specific activity in your application. This way, the user can initiate a search from any activity where the search dialog or widget is available, and the system starts the appropriate activity to perform the search and present results.

Other features available for the search dialog and widget include:
  • Voice search
  • Search suggestions based on recent queries
  • Search suggestions that match actual results in your application data

This following example shows you how to set up your application to provide a search interface that's assisted by the Android system to deliver search queries, using the search widget implementing SQLite fts3 module for fast search results.

Android SearchView using SQLite fts3 module example

Android SearchView using SQLite fts3 module example

Android SearchView using SQLite fts3 module example
The search widget is an instance of SearchView that you can place anywhere in your layout. By default, the search widget behaves like a standard EditText widget and doesn't do anything, but you can configure it so that the Android system handles all input events, delivers queries to the appropriate activity, and provides search suggestions (just like the search dialog). However, the search widget is available only in Android 3.0 (API Level 11) and higher.

To set up your application for this kind of assisted search, you need the following:

  • A searchable configuration
    • An XML file that configures some settings for the search dialog or widget. It includes settings for features such as voice search, search suggestion, and hint text for the search box.
  • A searchable activity
    • The Activity that receives the search query, searches your data, and displays the search results.
  • A search interface, provided by either:
    • The search dialog
      • By default, the search dialog is hidden, but appears at the top of the screen when the user presses the device SEARCH button (when available) or another button in your user interface.
    • Or, a SearchView widget

Using the search widget allows you to put the search box anywhere in your activity. Instead of putting it in your activity layout, however, it's usually more convenient for users as an action view in the Action Bar.

If your data is stored in a SQLite database on the device, performing a full-text search (using FTS3, rather than a LIKE query) can provide a more robust search across text data and can produce results significantly faster...

The FTS3 and FTS4 extension modules allows users to create special tables with a built-in full-text index. The full-text index allows the user to efficiently query the database for all rows that contain one or more words, even if the table contains many large documents.

Source for searchable.xml, the searchable configuration

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android=""
    android:label="@string/search_label" android:hint="@string/search_hint" />

Source for strings.xml

<?xml version="1.0" encoding="utf-8"?>
    <string name="hello">Hello World, SearchViewActivity!</string>
    <string name="app_name">Search View</string>
    <string name="search_label">Customers</string>
    <string name="search_hint">Search Customers</string>
    <string name="settings_description">List of Customers</string>

Source for AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android=""
    <uses-sdk android:minSdkVersion="13" />

    <application android:icon="@drawable/icon" android:label="@string/app_name"
        <activity android:name=".SearchViewActivity"
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
                <action android:name="android.intent.action.SEARCH" />
            <meta-data android:name=""
                android:resource="@xml/searchable" />


Source for main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=""
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    <LinearLayout android:layout_width="0dp" android:id="@+id/linearLayout1"
        android:layout_height="match_parent" android:layout_weight="30"
        <LinearLayout android:id="@+id/leftLayout"
            android:layout_width="match_parent" android:orientation="vertical"
            android:layout_height="wrap_content" android:paddingBottom="50dp">
            <SearchView android:layout_width="wrap_content"
                android:layout_height="wrap_content" android:id="@+id/search" />
            <ListView android:layout_width="fill_parent" android:id="@+id/list"
                android:layout_height="wrap_content" />
    <LinearLayout android:id="@+id/linearLayout2"
        android:layout_height="match_parent" android:orientation="vertical"
        android:layout_weight="70" android:layout_width="0dp">
        <LinearLayout android:id="@+id/linearLayout5"
            android:layout_height="wrap_content" android:orientation="horizontal"
            android:paddingBottom="10dp" android:layout_gravity="right"
            <TextView android:text="Customer Information" android:textStyle="bold"
                android:layout_height="wrap_content" android:id="@+id/textView6"
                android:textSize="25sp" android:layout_width="wrap_content"
                android:layout_weight="1" />
            <TextView android:text="Date: " android:textStyle="bold"
                android:layout_height="wrap_content" android:id="@+id/textView5"
                android:textSize="25sp" android:layout_width="wrap_content" />
            <TextView android:layout_width="wrap_content"
                android:layout_height="wrap_content" android:id="@+id/inspectionDate"
                android:textSize="25sp" android:paddingRight="25sp"/>
        <LinearLayout android:id="@+id/rightLayout"
            android:layout_width="match_parent" android:orientation="vertical"
            android:layout_height="wrap_content" android:paddingTop="25dp">

Source for customerinfo.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=""
    android:id="@+id/customerLayout" android:layout_width="match_parent"
    android:layout_height="wrap_content" android:orientation="vertical">
    <RelativeLayout android:id="@+id/relativeLayout1"
        android:layout_width="match_parent" android:layout_height="wrap_content">
        <TextView android:id="@+id/customer" android:layout_width="wrap_content"
            android:layout_height="wrap_content" style="@android:style/TextAppearance.Medium" android:paddingRight="5sp"/>
        <TextView android:id="@+id/name" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_below="@id/customer"
            style="@android:style/TextAppearance.Small" />
        <TextView android:id="@+id/address" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_below="@id/name"
            style="@android:style/TextAppearance.Small" />
        <TextView android:id="@+id/city" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_below="@id/address"
            style="@android:style/TextAppearance.Small" android:paddingRight="2sp"/>
        <TextView android:id="@+id/comma" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_below="@id/address" android:layout_toRightOf="@id/city"
            style="@android:style/TextAppearance.Small" android:paddingRight="2sp" android:text=","/>
        <TextView android:id="@+id/state" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_below="@id/address" android:layout_toRightOf="@id/comma"
            style="@android:style/TextAppearance.Small" android:paddingRight="2sp"/>
        <TextView android:id="@+id/zipCode" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_below="@id/address" android:layout_toRightOf="@id/state"
            style="@android:style/TextAppearance.Small" />   

Source for customerresult.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=""
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent" android:padding="5dp">
    <RelativeLayout android:id="@+id/relativeLayout1"
        android:layout_width="match_parent" android:layout_height="wrap_content">
        <TextView android:id="@+id/scustomer" android:layout_width="wrap_content"
            android:layout_height="wrap_content" style="@android:style/TextAppearance.Medium"
            android:paddingRight="5sp" />
        <TextView android:id="@+id/sname" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_toRightOf="@id/scustomer"
            style="@android:style/TextAppearance.Small" />
        <TextView android:id="@+id/saddress" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_below="@id/scustomer"
            style="@android:style/TextAppearance.Small" />
        <TextView android:id="@+id/scity" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_below="@id/saddress"
            style="@android:style/TextAppearance.Small" android:paddingRight="2sp" />
        <TextView android:id="@+id/scomma" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_below="@id/saddress"
            android:layout_toRightOf="@id/scity" style="@android:style/TextAppearance.Small"
            android:paddingRight="2sp" android:text=","/>   
        <TextView android:id="@+id/sstate" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_below="@id/saddress"
            android:layout_toRightOf="@id/scomma" style="@android:style/TextAppearance.Small"
            android:paddingRight="2sp" />
        <TextView android:id="@+id/szipCode" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_below="@id/saddress"
            android:layout_toRightOf="@id/sstate" style="@android:style/TextAppearance.Small" />

Source for

package com.as400samplecode;

public class Customer {
    String customer = null;
    String name = null;
    String address1 = null;
    String address2 = null;
    String city = null;
    String state = null;
    String zipCode = null;
    public String getCustomer() {
        return customer;
    public void setCustomer(String customer) {
        this.customer = customer;
    public String getName() {
        return name;
    public void setName(String name) { = name;
    public String getAddress1() {
        return address1;
    public void setAddress1(String address1) {
        this.address1 = address1;
    public String getAddress2() {
        return address2;
    public void setAddress2(String address2) {
        this.address2 = address2;
    public String getCity() {
        return city;
    public void setCity(String city) { = city;
    public String getState() {
        return state;
    public void setState(String state) {
        this.state = state;
    public String getZipCode() {
        return zipCode;
    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;

Source for

package com.as400samplecode;

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

    public static final String KEY_ROWID = "rowid";
    public static final String KEY_CUSTOMER = "customer";
    public static final String KEY_NAME = "name";
    public static final String KEY_ADDRESS = "address";
    public static final String KEY_ADDRESS1 = "address1";
    public static final String KEY_ADDRESS2 = "address2";
    public static final String KEY_CITY = "city";
    public static final String KEY_STATE = "state";
    public static final String KEY_ZIP = "zipCode";
    public static final String KEY_SEARCH = "searchData";

    private static final String TAG = "CustomersDbAdapter";
    private DatabaseHelper mDbHelper;
    private SQLiteDatabase mDb;

    private static final String DATABASE_NAME = "CustomerData";
    private static final String FTS_VIRTUAL_TABLE = "CustomerInfo";
    private static final int DATABASE_VERSION = 1;

    //Create a FTS3 Virtual Table for fast searches
    private static final String DATABASE_CREATE =
        KEY_CUSTOMER + "," +
        KEY_NAME + "," +
        KEY_ADDRESS1 + "," +
        KEY_ADDRESS2 + "," +
        KEY_CITY + "," +
        KEY_STATE + "," +
        KEY_ZIP + "," +
        KEY_SEARCH + "," +
        " UNIQUE (" + KEY_CUSTOMER + "));";

    private final Context mCtx;

    private static class DatabaseHelper extends SQLiteOpenHelper {

        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);

        public void onCreate(SQLiteDatabase db) {
            Log.w(TAG, DATABASE_CREATE);

        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");

    public CustomersDbAdapter(Context ctx) {
        this.mCtx = ctx;

    public CustomersDbAdapter open() throws SQLException {
        mDbHelper = new DatabaseHelper(mCtx);
        mDb = mDbHelper.getWritableDatabase();
        return this;

    public void close() {
        if (mDbHelper != null) {

    public long createCustomer(String customer, String name, String address1, String address2, String city, String state, String zipCode) {

        ContentValues initialValues = new ContentValues();
        String searchValue =     customer + " " + 
                                name + " " + 
                                address1 + " " + 
                                city + " " + 
                                state + " " + 
        initialValues.put(KEY_CUSTOMER, customer);
        initialValues.put(KEY_NAME, name);
        initialValues.put(KEY_ADDRESS1, address1);
        initialValues.put(KEY_ADDRESS2, address2);
        initialValues.put(KEY_CITY, city);
        initialValues.put(KEY_STATE, state);
        initialValues.put(KEY_ZIP, zipCode);
        initialValues.put(KEY_SEARCH, searchValue);

        return mDb.insert(FTS_VIRTUAL_TABLE, null, initialValues);

    public Cursor searchCustomer(String inputText) throws SQLException {
        Log.w(TAG, inputText);
        String query = "SELECT docid as _id," + 
        KEY_CUSTOMER + "," +
        KEY_NAME + "," +
        "(" + KEY_ADDRESS1 + "||" + 
        "(case when " + KEY_ADDRESS2 +  "> '' then '\n' || " + KEY_ADDRESS2 + " else '' end)) as " +  KEY_ADDRESS +"," +
        KEY_ADDRESS1 + "," +
        KEY_ADDRESS2 + "," +
        KEY_CITY + "," +
        KEY_STATE + "," +
        KEY_ZIP +
        " from " + FTS_VIRTUAL_TABLE +
        " where " +  KEY_SEARCH + " MATCH '" + inputText + "';";
        Log.w(TAG, query);
        Cursor mCursor = mDb.rawQuery(query,null);

        if (mCursor != null) {
        return mCursor;


    public boolean deleteAllCustomers() {

        int doneDelete = 0;
        doneDelete = mDb.delete(FTS_VIRTUAL_TABLE, null , null);
        Log.w(TAG, Integer.toString(doneDelete));
        return doneDelete > 0;



Source for

package com.as400samplecode;

import java.util.Calendar;

import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;

public class SearchViewActivity extends Activity implements SearchView.OnQueryTextListener,
SearchView.OnCloseListener {

    private ListView mListView;
    private SearchView searchView;
    private CustomersDbAdapter mDbHelper;

    private TextView inspectionDate;
    private TextView customerText;
    private TextView nameText;
    private TextView addressText;
    private TextView cityText;
    private TextView stateText;
    private TextView zipCodeText;

    public void onCreate(Bundle savedInstanceState) {

        searchView = (SearchView) findViewById(;

        mListView = (ListView) findViewById(;
        inspectionDate = (TextView) findViewById(;

        mDbHelper = new CustomersDbAdapter(this);;

        //Clean all Customers
        //Add some Customer data as a sample
        mDbHelper.createCustomer("PIZZA1", "Pizza Hut", "1107 West Adams Boulevard", "", "Los Angeles", "CA", "90007");
        mDbHelper.createCustomer("PIZZA2", "Pizza Hut", "1562 West Pico Boulevard", "", "Los Angeles", "CA", "90015");
        mDbHelper.createCustomer("PIZZA3", "Pizza Hut", "718 South Los Angeles Street", "", "Los Angeles", "CA", "90014");
        mDbHelper.createCustomer("PIZZA4", "Pizza Hut", "2542 West Temple Street", "", "Los Angeles", "CA", "90026");
        mDbHelper.createCustomer("PIZZA5", "Pizza Hut", "4329 North Figueroa Street", "", "Los Angeles", "CA", "90065");
        mDbHelper.createCustomer("PIZZA6", "Pizza Hut", "4351 South Central Avenue", "", "Los Angeles", "CA", "90011");
        mDbHelper.createCustomer("SUB1", "Subway", "975 West Jefferson", "", "Los Angeles", "CA", "90007");
        mDbHelper.createCustomer("SUB2", "Subway", "2805 South Figueroa Street", "", "Los Angeles", "CA", "90007");
        mDbHelper.createCustomer("SUB3", "Subway", "198 South Vermont Avenue", "", "Los Angeles", "CA", "90004");
        mDbHelper.createCustomer("SUB4", "Subway", "504 West Olympic Boulevard", "", "Los Angeles", "CA", "90015");


    protected void onDestroy() {
        if (mDbHelper  != null) {

    public boolean onQueryTextChange(String newText) {
        showResults(newText + "*");
        return false;

    public boolean onQueryTextSubmit(String query) {
        showResults(query + "*");
        return false;

    public boolean onClose() {
        return false;

    private void showResults(String query) {

        Cursor cursor = mDbHelper.searchCustomer((query != null ? query.toString() : "@@@@"));

        if (cursor == null) {
        } else {
            // Specify the columns we want to display in the result
            String[] from = new String[] {

            // Specify the Corresponding layout elements where we want the columns to go
            int[] to = new int[] {,

            // Create a simple cursor adapter for the definitions and apply them to the ListView
            SimpleCursorAdapter customers = new SimpleCursorAdapter(this,R.layout.customerresult, cursor, from, to);

            // Define the on-click listener for the list items
            mListView.setOnItemClickListener(new OnItemClickListener() {
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    // Get the cursor, positioned to the corresponding row in the result set
                    Cursor cursor = (Cursor) mListView.getItemAtPosition(position);

                    // Get the state's capital from this row in the database.
                    String customer = cursor.getString(cursor.getColumnIndexOrThrow("customer"));
                    String name = cursor.getString(cursor.getColumnIndexOrThrow("name"));
                    String address = cursor.getString(cursor.getColumnIndexOrThrow("address"));
                    String city = cursor.getString(cursor.getColumnIndexOrThrow("city"));
                    String state = cursor.getString(cursor.getColumnIndexOrThrow("state"));
                    String zipCode = cursor.getString(cursor.getColumnIndexOrThrow("zipCode"));
                    //Check if the Layout already exists
                    LinearLayout customerLayout = (LinearLayout)findViewById(;
                    if(customerLayout == null){
                        //Inflate the Customer Information View 
                        LinearLayout leftLayout = (LinearLayout)findViewById(;
                        View customerInfo = getLayoutInflater().inflate(R.layout.customerinfo, leftLayout, false);

                    //Get References to the TextViews
                    customerText = (TextView) findViewById(;
                    nameText = (TextView) findViewById(;
                    addressText = (TextView) findViewById(;
                    cityText = (TextView) findViewById(;
                    stateText = (TextView) findViewById(;
                    zipCodeText = (TextView) findViewById(;
                    // Update the parent class's TextView

    private void displayDate() {

        final Calendar c = Calendar.getInstance();

                new StringBuilder()
                // Month is 0 based so add 1
                .append(c.get(Calendar.MONTH) + 1).append("/")
                .append(c.get(Calendar.YEAR)).append(" "));

Tip: How to add voice search? See sample searchable configuration !
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android=""
    android:label="@string/search_label" android:hint="@string/search_hint"
    android:voiceSearchMode="showVoiceSearchButton|launchRecognizer" />


  1. Great tutorial :) Thank you very much :D

  2. can u give me the source code of this tutorial?? thanks...

  3. I have a content provider with some data in it and I want to search these data.
    Do I have to replace my content provider with the implementation above or implement a CustomersDbAdapter and fill it with the data from my content provider?

  4. plz give me code on my id

  5. i deleted searchable.xml still working searchable.xml what is the primary purpose of this xml

  6. Perfecto sirvió de mucha ayuda

  7. Thanks for Tutorial but didn´t understand the things with the different xml files.
    Can you send me pls the whole project?

  8. pls send me the source code to this email id

  9. pls send me the source code pls


  10. send me the source code pls


  11. send me the source code pls...

  12. Please send me the project to
    Thanks in advance.

  13. send me code please

  14. that is nice code. please send whole project to

  15. My frined thank you for this beautiful example.

  16. Plz send me the project

  17. Hi!Very nice blog!Please send me too this awesome project to ,thanks!

  18. hi..very nice example/code...please send me this lovely project example at

  19. Nice blog! Please send me this awesome project to ,thanks!

  20. Great code my friend, verry clean, and clear. thanks.

  21. Please send me this awesome project
    my mail :
    thank you!!

  22. Excellent signal my pal, verry thoroughly clean, as well as obvious. many thanks.

    elo boost

    Cheap Fifa 14 Coins

  23. Hey think you can send this to me as well?

  24. Awesome. Please send me project to e-mail:

  25. can u please send me the project code at:
    i'll b thankful to u

  26. great code can you send me the code at

  27. Please send me this project
    my mail :

    thank and best regard!

  28. Incredible. I discovered the youtube . com movie by which a person informed exactly what paints you utilize, however We can't discover the manufacturer on the internet. Would you make sure you inform me personally generate an income will find all of them? Many thanks! I really like your projects.

    fifa coins
    elo boost
    fut 14 coins
    fifa coins

  29. In the past never did I feel the great significance fifa 14 coins of gratefulness. I had been holding that everything about life cheap fifa 14 coins would become nothing but turn back to dust at the end of life. Maybe at that time I had seen through life and death, thinking that life cheap fifa 14 coins was running to the end unceasingly regardless of our sentimental sigh

  30. Very good code, Kindly send me the code to if you could. Thank you very much.

  31. Awesome post !!
    plss mail the code to
    Thank you

  32. Nice code. Pls send code to
    Thank you.

  33. Nice tutorial. Pls send code to

  34. Awesome - I think i can use this - please send the complete code to

  35. Exclusively, players will come across a little daughter cyberbullying victim known as Expect (over) and ought to aid the woman's stand up to bullies.Players can make use of sensitive, realistic messaging tactics made in collaboration along with cyberbullying charity Your Cybersmile Groundwork in the game.The actual cyberbullying missions introduced lately and possess seen over 500,000 people thus far.In accordance with Pixelberry, as developers started out writing the actual cyberbullying-themed quests, a player arrived at in the market to all of them knowing thoughts of suicide.Following calling a serious event hotline to supply he or she together with guidance, programmers started to understand how a lot of a direct effect they could dress in the matter with good University Account.

    Cheap Fifa 15 Coins

    Fut 15 coins

  36. pls send me the complete code thanks

  37. I favor java to create video gaming programs. To begin along with formerly acquired tend to be suggesting that require in order to.

    fut 15 coins

  38. pls send me the source code thanks

  39. since FIFA 15 is going to release, we keep pace with times selling FIFA 15 Coins on every consoles. No doubt, we are reliable online sellers. If you need, don't be hesitate to visit:

  40. pls send me the source code, thanks in advance

  41. Hello! Amazing example :) can you send me the source code to Thanks in advance!

  42. Could I also get the complete code sent to

  43. I would really be grateful if I can also have your complete code of this to my email thanks :)

  44. pls send me the complete code thanks

  45. To begin along with formerly acquired tend to be suggesting that require in order to. fifa coins

  46. source code please!! thanks.

  47. Very good code, Kindly send me the code to if you could. Thank you very much.

  48. Awesome tutorial. Could you please send code to Thanks.

    1. is the correct email. thanks

  49. Good tutorial :) Can you send me the whole project?

  50. Awesome tutorial. Could you please send code to Thanks.

  51. great job. pls send to

  52. Thanks, may i please have the source code.

  53. Thanks, very nice tutorial, could you please send code to

  54. Old is Gold they say, kindly email the source code to