Android Listview using Custom Adapter and SQLite

Android Listview using Custom Adapter and SQLite

This tutorial will show you how to create a note-taking app using a custom listview. You will also learn to add, delete and list data from SQLite.

Create the ListView layout

Start by adding a ListView item to your main layout file in res/layout.

File: activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
    </ListView>

</LinearLayout>

Once that’s done, create a new file called rowlayout.xml in the same folder res/layout. This is how each row in the listview will look like. You can customize this view to add an image for each row or change the font size or height of each row.

File: rowlayout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="35dp"
    android:layout_weight="1"
    android:paddingLeft="5dp"
    android:paddingRight="5dp"
    android:paddingTop="5dp" >

    <TextView
        android:id="@+id/label"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:textSize="22sp" />

</LinearLayout>

This last bit for the layout adds a add sign on to the menu. We’ll need this later to add new entries. Go to res/menu and edit the main.xml.

File: menu/main.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.ahotbrew.listviewsqlite.MainActivity" >

    <item android:id="@+id/action_add"
        android:showAsAction="always"
        android:title="Add"/>
</menu>

If you run the app now, you will see an empty list with the Add button in the top menu.

Create the SQLite database

Go to your android project src folder and create a new java file.

File: DatabaseHelper.java

package com.ahotbrew.listviewsqlite;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DatabaseHelper extends SQLiteOpenHelper {

	private static final int DATABASE_VERSION = 1;
	private static final String DATABASE_NAME = "MyNotes";
	private static final String DATABASE_TABLE_NAME = "todo";
	public static final String COLID = "MyNotesID";
	public static final String COLTITLE = "Title";

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

	/**
	 * This runs once after the installation and creates a database
	 */
	@Override
	public void onCreate(SQLiteDatabase db) {
		// Here we are creating two columns in our database.
		// MyNotesID, which is the primary key and Title which will hold the
		// todo text
		db.execSQL("CREATE TABLE " + DATABASE_TABLE_NAME + " (" + COLID
				+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + COLTITLE + " TEXT)");

	}

	/**
	 * This would run after the user updates the app. This is in case you want
	 * to modify the database
	 */
	@Override
	public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
		// TODO Auto-generated method stub
	}

	/**
	 * This method adds a record to the database. All we pass in is the todo
	 * text
	 */
	public long addRecord(String title) {
		SQLiteDatabase db = this.getWritableDatabase();
		ContentValues cv = new ContentValues();
		cv.put(COLTITLE, title);

		return db.insert(DATABASE_TABLE_NAME, null, cv);
	}

	/**
	 * //This method returns all notes from the database
	 */
	public ArrayList<MyNotes> getAllNotes() {
		SQLiteDatabase db = this.getReadableDatabase();
		ArrayList<MyNotes> listItems = new ArrayList<MyNotes>();

		Cursor cursor = db.rawQuery("SELECT * from " + DATABASE_TABLE_NAME,
				new String[] {});

		if (cursor.moveToFirst()) {
			do {
				MyNotes note = new MyNotes();

				note.Id = cursor.getInt(cursor.getColumnIndex(COLID));

				note.Title = cursor.getString(cursor.getColumnIndex(COLTITLE));

				listItems.add(note);
			} while (cursor.moveToNext());
		}

		cursor.close();

		return listItems;
	}

	/*
	 * //This method deletes a record from the database.
	 */
	public void deleteNote(long id) {
		SQLiteDatabase db = this.getReadableDatabase();

		String string = String.valueOf(id);
		db.execSQL("DELETE FROM " + DATABASE_TABLE_NAME + " WHERE " + COLID
				+ "=" + id + "");
	}
}

The database code is all setup, we can go ahead and implement the code for the listview.

Create custom adapter and wire up listview to our database

Open your MainActivity.java file and add the code below.

File: MainActivity.java


package com.ahotbrew.listviewsqlite;

import java.util.ArrayList;

import com.ahotbrew.listviewsqlite.R;

import android.app.ActionBar.LayoutParams;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends Activity {

	// Out custom adapter
	MySimpleArrayAdapter adapter;

	// contains our listview items
	ArrayList<MyNotes> listItems;

	// database
	DatabaseHelper DatabaseHelper;

	// list of todo titles
	ArrayList<String> newData;

	// contains the id of the item we are about to delete
	public int deleteItem;

	// EditText field for adding new items to the list
	EditText editText2;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		// We're getting our listView by the id
		ListView listView = (ListView) findViewById(R.id.list);

		// Creating a new instance of our DatabaseHelper, which we've created
		// earlier
		DatabaseHelper = new DatabaseHelper(this);

		// This returns a list of all our current available notes
		listItems = DatabaseHelper.getAllNotes();

		newData = new ArrayList<String>();

		// Assigning the title to our global property so we can access it
		// later after certain actions (deleting/adding)
		for (MyNotes note : listItems) {
			newData.add(note.Title);
		}

		// We're initialising our custom adapter with all our data from the
		// database
		adapter = new MySimpleArrayAdapter(this, newData);

		// Assigning the adapter to ListView
		listView.setAdapter(adapter);

		// Assigning an event to the listview
		// This event will be used to delete records
		listView.setOnItemLongClickListener(myClickListener);
	}

	/**
	 * This adapter will create your list view row by row
	 */
	public class MySimpleArrayAdapter extends ArrayAdapter<String> {
		private final Context context;
		private final ArrayList<String> values;

		public MySimpleArrayAdapter(Context context, ArrayList<String> values) {
			super(context, R.layout.rowlayout, values);

			this.context = context;
			this.values = values;
		}

		/**
		 * Here we go and get our rowlayout.xml file and set the textview text.
		 * This happens for every row in your listview.
		 */
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			LayoutInflater inflater = (LayoutInflater) context
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

			View rowView = inflater.inflate(R.layout.rowlayout, parent, false);

			TextView textView = (TextView) rowView.findViewById(R.id.label);

			// Setting the text to display
			textView.setText(values.get(position));

			return rowView;
		}
	}

	/**
	 * On a long click delete the selected item
	 */
	public OnItemLongClickListener myClickListener = new OnItemLongClickListener() {
		@Override
		public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
				int arg2, long arg3) {
			// Assigning the item position to our global variable
			// So we can access it within our AlertDialog below
			deleteItem = arg2;

			// Creating a new alert dialog to confirm the delete
			AlertDialog alert = new AlertDialog.Builder(arg1.getContext())
					.setTitle("Delete " + listItems.get(deleteItem).Title)
					.setPositiveButton("Ok",
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog,
										int whichButton) {
									// Retrieving the note from our listItems
									// property, which contains all notes from
									// our database
									MyNotes note = listItems.get(deleteItem);

									// Deleting it from the ArrayList<string>
									// property which is linked to our adapter
									newData.remove(deleteItem);

									// Deleting the note from our database
									DatabaseHelper.deleteNote(note.Id);

									// Tell the adapter to update the list view
									// with the latest changes
									adapter.notifyDataSetChanged();

									dialog.dismiss();
								}
							})
					.setNegativeButton("Cancel",
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog,
										int whichButton) {
									// When you press cancel, just close the
									// dialog
									dialog.cancel();
								}
							}).show();

			return false;
		}
	};

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);

		return true;
	}

	/**
	 * This method is called when you press any button in your menu We've named
	 * our add button action_add in our menu.xml file
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle presses on the action bar items
		switch (item.getItemId()) {
		case R.id.action_add:
			showCreateNote();
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}

	/**
	 * This simply shows a alert dialog asking for the todo text
	 */
	public void showCreateNote() {
		// Creating a dynamical edittext for our alert dialog
		editText2 = new EditText(this);
		editText2.setId(9999);
		editText2.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.MATCH_PARENT));
		editText2.setHint("Enter your note");

		AlertDialog alert = new AlertDialog.Builder(this)
				.setTitle("Create Note")
				.setView(editText2)
				.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int whichButton) {

						if (editText2.getText().toString().length() > 0) {
							// Adding the new todo text to our database
							long Id = DatabaseHelper.addRecord(editText2
									.getText().toString());

							// Create a new MyNotes object to add it to our
							// global property listItems
							MyNotes note = new MyNotes();
							note.Id = (int) Id;
							note.Title = editText2.getText().toString();

							listItems.add(note);

							newData.add(note.Title);

							adapter.notifyDataSetChanged();
						}

						dialog.dismiss();
						// This hides the android keyboard
						InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
						imm.toggleSoftInput(
								InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
					}
				})
				.setNegativeButton("Cancel",
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog,
									int whichButton) {
								dialog.cancel();

								// This hides the android keyboard
								InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
								imm.toggleSoftInput(
										InputMethodManager.HIDE_IMPLICIT_ONLY,
										0);

							}
						}).show();

		// We are automatically focusing on the editText field
		if (editText2.requestFocus())
			;
		{
			// This brings out the android keyboard as soon as we focus on the
			// editText area
			InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
			imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
		}
	}
}

In our OnCreate method you can see how we retrieve and list all our records from the database.
MySimpleArrayAdapter is our custom adapter that assigns a view for each row.
MyClickListener is called every time you press a row for few seconds to delete it from SQLite.

Now you should be able to add, delete list all notes.

Sit back, take a sip from your hot brew and run your project.

Don’t forget to join or newsletter and get free android tutorials to enjoy with your hot brew.

  • A person necessarіly lend a hand to make critically articles I might state.
    This is the first time I fгequented your web page and
    up to now? I amɑzed with the reѕeaгch you mzdе to cгeate thiѕ particular puЬlish
    amazing. Ӎagnificent task!

  • Тhese are actually fantastic ideas in abkut blogging.
    You have touched some fastidious points here. Any way keep
    up wrinting.

  • Wow! This blog loօks еxactly like my old one!

    It’s on a entirely different topic but іt has pretty much the same page layoսt and design.
    Excellent choice of colors!

  • Mike Davis

    Thanks fo r the great example.
    Two things.
    One : I can’t work out is where/how to add the code to get rid of the error for myClickListener.

    Two: Cannot resolve symbol ‘LayoutParams’. Which class should be imported?

    Thanks

    • gurisingh

      Hi Mike

      One:
      Add the myClickListener within the MainActivity.

      Two:
      Add the package
      import android.view.ViewGroup;
      and then use it in this way: ViewGroup.LayoutParams

      Hope it helps.

  • Mikail İmza

    What I need to do for a 5-way data transfer job