Tutorial #79: Implement ListView with search functionality in Android

Hello everyone!

Android allows users to search any data that is available to them irrespective of whether the content is located on the device or the Internet. Post Android 3.0 (Honeycomb), a SearchView widget provides an interface for the user to enter a search query and submit a request to a search provider. It also shows a list of query suggestions or results, if available.

While implement search functionality in your Android application it is important to note that the search framework does not provide APIs to search your data. To perform a search, you need to use APIs appropriate for your data. For example, if your data is stored in an SQLite database, you should use the android.database.sqlite APIs to perform searches. In this tutorial, we will learn how to add the search functionality to our existing Android ListView.

Pre-requisites: Eclipse IDE, Android SDK

Step 1: Create Android project

Launch Eclipse IDE and create a new Android application project called AndroidListViewWithSearch with package name com.example

Step 2: Create Helper class for SQLite database

In this example, we will be storing our listview data inside a table of the SQLite database. We would be using a virtual table for faster and efficient access of data.

DbHelper.java

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 DbHelper {
   
    public static final String COLUMN_NAME = "fruits"; 
    private static final String TAG = "App";
    private DatabaseHelper myDbHelper;
    private SQLiteDatabase myDb;
 
    private static final String DATABASE_NAME = "Data";
    private static final String FTS_VIRTUAL_TABLE = "Info";
    private static final int DATABASE_VERSION = 1;
 
    //Create a Virtual Table for fast searches
    private static final String DATABASE_CREATE =
            "CREATE VIRTUAL TABLE " + FTS_VIRTUAL_TABLE + " USING fts3("
                    + COLUMN_NAME
                    + " UNIQUE (" + COLUMN_NAME + "));";
 
 
    private final Context context;
 
    private static class DatabaseHelper extends SQLiteOpenHelper {
 
        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }
 
 
        @Override
        public void onCreate(SQLiteDatabase db) {
            Log.w(TAG, DATABASE_CREATE);
            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 " + FTS_VIRTUAL_TABLE);
            onCreate(db);
        }
    }
 
    public DbHelper(Context ctx) {
        this.context = ctx;
    }
 
    public DbHelper open() throws SQLException {
        myDbHelper = new DatabaseHelper(context);
        myDb = myDbHelper.getWritableDatabase();
        return this;
    }
 
    public void close() {
        if (myDbHelper != null) {
            myDbHelper.close();
        }
    }
 
 
    public long createList(String name) {
 
        ContentValues initialValues = new ContentValues();
 
        initialValues.put(COLUMN_NAME, name);

        return myDb.insert(FTS_VIRTUAL_TABLE, null, initialValues);
 
    }
 
 
    public Cursor searchByInputText(String inputText) throws SQLException {
 
        String query = "SELECT docid as _id," +
                COLUMN_NAME +  " from " + FTS_VIRTUAL_TABLE +
                " where " + COLUMN_NAME + " MATCH '" + inputText + "';";
 
        Cursor mCursor = myDb.rawQuery(query,null);
 
        if (mCursor != null) {
            mCursor.moveToFirst();
        }
        return mCursor;
 
    }
 
 
    public boolean deleteAllNames() {
 
        int doneDelete = myDb.delete(FTS_VIRTUAL_TABLE, null , null);
        return doneDelete > 0;
 
    }
}

Step 3: Create customized list view

The BaseAdapter is the common base class of implementation for an Adapter that can be used in both ListView (by implementing the specialized ListAdapter interface). Let’s create our own Adapter as follows,

MyAdapter.java

package com.example;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.ArrayList;

public class MyAdapter extends BaseAdapter {

	private ArrayList myListItems;
	private LayoutInflater myLayoutInflater;

	public MyAdapter(Context context, ArrayList arrayList){

		myListItems = arrayList;
		myLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	}

	@Override
	public int getCount() {
		return myListItems.size();
	}

	@Override

	public Object getItem(int i) {
		return null;
	}

	@Override
	public long getItemId(int i) {
		return 0;
	}

	@Override

	public View getView(int position, View view, ViewGroup viewGroup) {


		ViewHolder holder;


		if (view == null) {
			holder = new ViewHolder();

			view = myLayoutInflater.inflate(R.layout.list_item, null);
			holder.itemName = (TextView) view.findViewById(R.id.list_item);


			view.setTag(holder);
		} else {

			holder = (ViewHolder)view.getTag();
		}


		String stringItem = myListItems.get(position).toString();
		if (stringItem != null) {
			if (holder.itemName != null) {
				//set the item name on the TextView
				holder.itemName.setText(stringItem);
			}
		}


		return view;

	}


	private static class ViewHolder {

		protected TextView itemName;
	}
}

Step 4: Make Activity searchable

In order to make our Android activity implement the search functionality, we need to add an IntentFilter in our AndroidManifest.xml file as follows,

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.MainActivity"
            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>

</manifest>

Once this is done, create a new folder called xml inside res. Add the following searchable.xml file to that folder.

searchable.xml

<?xml version="1.0" encoding="utf-8"?>
 
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
            android:label="@string/search_label"
            android:hint="@string/search_hint"/>

res/values/strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">AndroidListViewWithSearch</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Android ListView with Search Demo</string>
    <string name="search_label">Search</string>
    <string name="search_hint">Search items from ListView</string>

</resources>

Step 5: Create Activity class

Add the following code to the MainActivity class!

MainActivity.java

package com.example;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.database.Cursor;
import android.os.Handler;
import android.view.View;
import android.widget.*;
import java.util.ArrayList;


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

	private ListView myList;
	private SearchView searchView;
	private DbHelper mDbHelper;
	private MyAdapter defaultAdapter;
	@SuppressWarnings("rawtypes")
	private ArrayList<String> nameList;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_main);

		nameList = new ArrayList();

		
		//populate list
		nameList.add("Apples");
		nameList.add("Oranges");
		nameList.add("Grapes");
		nameList.add("Pineapples");
		nameList.add("Mangoes");
		nameList.add("Watermelons");
		nameList.add("Strawberries");
		nameList.add("Bananas");
		nameList.add("Apricots");
		nameList.add("Olives");
		nameList.add("Peaches");
		nameList.add("Jackfruits");
		
		myList = (ListView) findViewById(R.id.list);

		defaultAdapter = new MyAdapter(MainActivity.this, nameList);
		myList.setAdapter(defaultAdapter);
		
		searchView = (SearchView) findViewById(R.id.search);
		searchView.setIconifiedByDefault(false);

		searchView.setOnQueryTextListener(this);
		searchView.setOnCloseListener(this);

		mDbHelper = new DbHelper(this);
		mDbHelper.open();

		//Clear all names
		mDbHelper.deleteAllNames();

		// Create the list of names which will be displayed on search
		for (String name : nameList) {
			mDbHelper.createList(name);
		}
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();

		if (mDbHelper  != null) {
			mDbHelper.close();
		}
	}

	@Override
	public boolean onClose() {
		myList.setAdapter(defaultAdapter);
		return false;
	}

	@Override
	public boolean onQueryTextSubmit(String query) {
		displayResults(query + "*");
		return false;
	}

	@Override
	public boolean onQueryTextChange(String newText) {
		if (!newText.isEmpty()){
			displayResults(newText + "*");
		} else {
			myList.setAdapter(defaultAdapter);
		}

		return false;
	}

	private void displayResults(String query) {

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

		if (cursor != null) {

			String[] from = new String[] {DbHelper.COLUMN_NAME};

			int[] to = new int[] {R.id.search_text_view};

			SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(this, R.layout.search_item, cursor, from, to);
			myList.setAdapter(cursorAdapter);

			//listview Click listener
			myList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
				public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

					Cursor cursor = (Cursor) myList.getItemAtPosition(position);

					String selectedName = cursor.getString(cursor.getColumnIndexOrThrow("name"));
					Toast.makeText(MainActivity.this, selectedName, 0).show();

					myList.setAdapter(defaultAdapter);

					for (int pos = 0; pos < nameList.size(); pos++) {
						if (nameList.get(pos).equals(selectedName)){
							position = pos;
							break;
						}
					}

					Handler handler = new Handler();
					final int finalPosition = position;
					handler.post(new Runnable() {
						@Override
						public void run() {

							myList.setSelection(finalPosition);
						}
					});

					searchView.setQuery("",true);
				}
			});

		}
	}
}

Save all changes and make sure no errors are present. Run the application on an Android device and you should see the following output!

output_1

output_2

Reference: Android Search

Karan Balkar About Karan Balkar
self proclaimed extraterrestrial fandroid, computer engineer, amateur gamer and die hard punk rock fan!

61 thoughts on “Tutorial #79: Implement ListView with search functionality in Android

  1. Hi! KARAN BALKAR, your tutorial is clean and nicely described. However, would you plz send me your xml file for layout? My email id is – “mizanmyself@yahoo.com”. Thank you in advance.

  2. Fantastic tutorial works well
    releasing my first android app as soon as I can interface this
    I’m trying to create list from database using simple cursor adapter but not compatible with search not compatible with void
    If you could show me or point me in the correct direction it would be most appreciated

  3. sir,
    i hav problm wid filter search list view. hw can i go to next activity by simply selecting random item from filter search listview. plz help me with code.

  4. Thanks bro…

    Can u know how to make search option at action bar? And
    How to make clickable list view?

    If you know, so plz mail me that code…

Leave a Reply

Your email address will not be published. Required fields are marked *