Building a TODO List app in Android using SQLite

January 22, 2013

Android SQLite Todo ListStoring data locally in Android is very easy. Here are few ways we can do it:

  1. Using SharedPreferences
  2. Using Files
  3. Using SQL databases.

This tutorial will tell you how to save data using SQL databases. For this we are taking a very simple application which stores a very simple list of tasks with their boolean status: done or not done.

The Database

The database contains only one table called “task” which has the following columns:

  1. Id
  2. Task
  3. Status

This tutorial will show us how to save data in a SQL database. For this we are would build a very simple application which stores a list of tasks with their boolean status(whether done or not done).<!>

Creating the project

Create a project in eclipse with a activity called ViewTaskActivity like the following:

Android SQLite Project Setup

Here is the manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android=""
   android:versionName="1.0" >
       android:targetSdkVersion="17" />
       android:theme="@style/AppTheme" >
           android:label="@string/app_name" >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

Setting up the database helper

Now in the app you need to create a simple java class to represent the task. This will help us when we set up operations for the database.

  1. package com.example.tasker;
  2. public class Task {
  3.     private String taskName;
  4.     private int status;
  5.     private int id;
  6.     public Task()
  7.     {
  8.         this.taskName=null;
  9.         this.status=0;
  10.     }
  11.     public Task(String taskName, int status) {
  12.         super();
  13.         this.taskName = taskName;
  14.         this.status = status;
  15.     }
  16.     public int getId() {
  17.         return id;
  18.     }
  19.     public void setId(int id) {
  20. = id;
  21.     }
  22.     public String getTaskName() {
  23.         return taskName;
  24.     }
  25.     public void setTaskName(String taskName) {
  26.         this.taskName = taskName;
  27.     }
  28.     public int getStatus() {
  29.         return status;
  30.     }
  31.     public void setStatus(int status) {
  32.         this.status = status;
  33.     }
  34. }

In Android we need to set up a database helper which will help in performing operations on the database. For now I am only going to define three database operations: Create, Read and Update.

In order to create a Database helper, we create a class that would extend SQLiteOpenHelper. And you also need to put in two methods: on Create() and onUpgrade().

onCreate() is called only one time when the database is accessed the first time. It will contain all the table create statements. And onUpgrade() is called when database is modifed in any way. So here is the helper class initially.

  1. package com.example.tasker;
  2. import android.content.ContentValues;
  3. import android.content.Context;
  4. import android.database.sqlite.SQLiteDatabase;
  5. import android.database.sqlite.SQLiteDatabase.CursorFactory;
  6. import android.database.sqlite.SQLiteOpenHelper;
  7. public class TaskerDbHelper extends SQLiteOpenHelper {
  8.     private static final int DATABASE_VERSION = 1;
  9.     // Database Name
  10.     private static final String DATABASE_NAME = “taskerManager”;
  11.     // tasks table name
  12.     private static final String TABLE_TASKS = “tasks”;
  13.     // tasks Table Columns names
  14.     private static final String KEY_ID = “id”;
  15.     private static final String KEY_TASKNAME = “taskName”;
  16.     private static final String KEY_STATUS = “status”;
  17.     public TaskerDbHelper(Context context) {
  18.         super(context, DATABASE_NAME, null, DATABASE_VERSION);
  19.     }
  20.     @Override
  21.     public void onCreate(SQLiteDatabase db) {
  22.         String sql = “CREATE TABLE IF NOT EXISTS “ + TABLE_TASKS + ” ( “
  23.                 + KEY_ID + “INTEGER PRIMARY KEY AUTOINCREMENT, “
  24.                 + KEY_TASKNAME+ ” TEXT, “
  25.                 + KEY_STATUS + ” INTEGER)”;
  26.         db.execSQL(sql);
  27.     }
  28.     @Override
  29.     public void onUpgrade(SQLiteDatabase db, int oldV, int newV) {
  30.          // Drop older table if existed
  31.         db.execSQL(“DROP TABLE IF EXISTS “ + TABLE_TASKS);
  32.         // Create tables again
  33.         onCreate(db);
  34.     }
  35. }

Adding Create Operation

Now as I said we need to add three operations on this database. Lets start with Create.

public void addTask(Task task) {
SQLiteDatabase db = this.getWritableDatabase();

ContentValues values = new ContentValues();
values.put(KEY_TASKNAME, task.getTaskName()); // task name
// status of task- can be 0 for not done and 1 for done
values.put(KEY_STATUS, task.getStatus());

// Inserting Row
db.insert(TABLE_TASKS, null, values);
db.close(); // Closing database connection

Adding a Read Operation

We will read from database and store all values in an Array list.

public List<Task> getAllTasks() {
List<Task> taskList = new ArrayList<Task>();
// Select All Query
String selectQuery = "SELECT  * FROM " + TABLE_TASKS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Task task = new Task();
// Adding contact to list
} while (cursor.moveToNext());
// return task list
return taskList;

The update operation

In this app I only need to update the status of the task. Status is 0 if task is not done and 1 if done.

public void updateTask(Task task) {
// updating row
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_TASKNAME, task.getTaskName());
values.put(KEY_STATUS, task.getStatus());
db.update(TABLE_TASKS, values, KEY_ID + " = ?",
new String[]{String.valueOf(task.getId())});

The View

I will try to include all options in one view so that the App has two seections in one screen. On the top is a EditText and an “Add” button to add tasks. And below that are the tasks in a ListView. The xml file for this view is as follows:


  1. <RelativeLayout xmlns:android=“”
  2.    xmlns:tools=“”
  3.    android:layout_width=“match_parent”
  4.    android:layout_height=“match_parent”
  5.    tools:context=“.ViewTask” >
  6.     <EditText
  7.        android:id=“@+id/editText1″
  8.        android:layout_width=“wrap_content”
  9.        android:layout_height=“wrap_content”
  10.        android:layout_alignParentLeft=“true”
  11.        android:layout_alignParentTop=“true”
  12.        android:ems=“10” >
  13.         <requestFocus />
  14.     </EditText>
  15.     <Button
  16.        android:id=“@+id/button1″
  17.        android:layout_width=“wrap_content”
  18.        android:layout_height=“wrap_content”
  19.        android:layout_alignParentRight=“true”
  20.        android:layout_alignParentTop=“true”
  21.        android:layout_marginRight=“14dp”
  22.        android:text=“@string/button”
  23.        android:onClick=“addTaskNow”/>
  24.     <ListView
  25.        android:id=“@+id/listView1″
  26.        android:layout_width=“match_parent”
  27.        android:layout_height=“wrap_content”
  28.        android:layout_alignParentLeft=“true”
  29.        android:layout_below=“@+id/button1″ >
  30.     </ListView>
  31. </RelativeLayout>

This list view is going to have a different view inside it. A checkbox to show status of the task as well as the description of the task. Pretty simple and easy right??? Lets see how that works out.

Create a new xml file in your layout folder called list_inner_view.xml and add the following controls in it:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android=""
   android:layout_height="match_parent" >
       android:text="CheckBox" />



For now as there are no tasks added our app looks like this

Android SQLite Project Task Screen

Adding the logic

Now to populate my list view I will need a custom data adapter so inside my activity class I am going to create a private class extending an ArrayAdapter. The class is inside the activity we created earlier.

private class MyAdapter extends ArrayAdapter<Task>
Context context;
List<Task> taskList=new ArrayList<Task>();
int layoutResourceId;
public MyAdapter(Context context, int layoutResourceId,
List<Task> objects) {
super(context, layoutResourceId, objects);
this.layoutResourceId = layoutResourceId;
/**This method will DEFINe what the view inside the list view will finally look like
* Here we are going to code that the checkbox state is the status of task and
* check box text is the task name

public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
View rowView = inflater.inflate(R.layout.list_inner_view, parent, false);
CheckBox chk=(CheckBox)rowView.findViewById(;
Task current=taskList.get(position);

return rowView;



Now you on start up of the app we need to add a few lines in the Activity OnCreate method

protected void onCreate(Bundle savedInstanceState) {
//db is a variable of type TaskerDbHelper
db=new TaskerDbHelper(this);
adapt=new MyAdapter(this,R.layout.list_inner_view , list);
ListView listTask=(ListView)findViewById(;

Next up is listing all the tasks in the list view and refreshing when ever a task is added. So in the xml finle don’t forget to declare the listener for button then add the following method to activity

So after adding task we can see this

Task Manage Android

Lastly we need to change status of task when the checkbox against it is checked. This is a complicated bit as we will need the ID of task which was checked and then proceed. So here is what we are going to do we are going to visit our adapter again and add a listener over there.

So here is the updated complete code of the activity.

  1. package com.example.tasker;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import android.os.Bundle;
  5. import;
  6. import android.content.Context;
  7. import android.database.sqlite.SQLiteDatabase;
  8. import android.util.Log;
  9. import android.view.LayoutInflater;
  10. import android.view.Menu;
  11. import android.view.View;
  12. import android.view.ViewGroup;
  13. import android.widget.ArrayAdapter;
  14. import android.widget.CheckBox;
  15. import android.widget.EditText;
  16. import android.widget.ListView;
  17. import android.widget.TextView;
  18. import android.widget.Toast;
  19. public class ViewTask extends Activity {
  20.     protected TaskerDbHelper db;
  21.     List<Task> list;
  22.     MyAdapter adapt;
  23.     @Override
  24.     protected void onCreate(Bundle savedInstanceState) {
  25.         super.onCreate(savedInstanceState);
  26.         setContentView(R.layout.activity_view_task);
  27.         db = new TaskerDbHelper(this);
  28.         list = db.getAllTasks();
  29.         adapt = new MyAdapter(this, R.layout.list_inner_view, list);
  30.         ListView listTask = (ListView) findViewById(;
  31.         listTask.setAdapter(adapt);
  32.     }
  33.     public void addTaskNow(View v) {
  34.         EditText t = (EditText) findViewById(;
  35.         String s = t.getText().toString();
  36.         if (s.equalsIgnoreCase(“”)) {
  37.             Toast.makeText(this, “enter the task description first!!”,
  38.                     Toast.LENGTH_LONG);
  39.         } else {
  40.             Task task = new Task(s, 0);
  41.             db.addTask(task);
  42.             Log.d(“tasker”, “data added”);
  43.             t.setText(“”);
  44.             adapt.add(task);
  45.             adapt.notifyDataSetChanged();
  46.         }
  47.     }
  48.     @Override
  49.     public boolean onCreateOptionsMenu(Menu menu) {
  50.         // Inflate the menu; this adds items to the action bar if it is present.
  51.         getMenuInflater().inflate(, menu);
  52.         return true;
  53.     }
  54.     private class MyAdapter extends ArrayAdapter<Task> {
  55.         Context context;
  56.         List<Task> taskList = new ArrayList<Task>();
  57.         int layoutResourceId;
  58.         public MyAdapter(Context context, int layoutResourceId,
  59.                 List<Task> objects) {
  60.             super(context, layoutResourceId, objects);
  61.             this.layoutResourceId = layoutResourceId;
  62.             this.taskList = objects;
  63.             this.context = context;
  64.         }
  65.         /**
  66.          * This method will DEFINe what the view inside the list view will
  67.          * finally look like Here we are going to code that the checkbox state
  68.          * is the status of task and check box text is the task name
  69.          */
  70.         @Override
  71.         public View getView(int position, View convertView, ViewGroup parent) {
  72.             CheckBox chk = null;
  73.             if (convertView == null) {
  74.                 LayoutInflater inflater = (LayoutInflater) context
  75.                         .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  76.                 convertView = inflater.inflate(R.layout.list_inner_view,
  77.                         parent, false);
  78.                 chk = (CheckBox) convertView.findViewById(;
  79.                 convertView.setTag(chk);
  80.                 chk.setOnClickListener(new View.OnClickListener() {
  81.                     @Override
  82.                     public void onClick(View v) {
  83.                         CheckBox cb = (CheckBox) v;
  84.                         Task changeTask = (Task) cb.getTag();
  85.                         changeTask.setStatus(cb.isChecked() == true ? 1 : 0);
  86.                         db.updateTask(changeTask);
  87.                         Toast.makeText(
  88.                                 getApplicationContext(),
  89.                                 “Clicked on Checkbox: “ + cb.getText() + ” is “
  90.                                         + cb.isChecked(), Toast.LENGTH_LONG)
  91.                                 .show();
  92.                     }
  93.                 });
  94.             } else {
  95.                 chk = (CheckBox) convertView.getTag();
  96.             }
  97.             Task current = taskList.get(position);
  98.             chk.setText(current.getTaskName());
  99.             chk.setChecked(current.getStatus() == 1 ? true : false);
  100.             chk.setTag(current);
  101.             Log.d(“listener”, String.valueOf(current.getId()));
  102.             return convertView;
  103.         }
  104.     }
  105. }

Now the finally when we check the checkbox our database will reflect changes as this

SQLite Data Insert Check

And the task will be checked

Todo App in Android

So that is it for now folks. Hope you enjoyed this tutorial. I had fun making it!!! With some more work it can be turned into a full fledged check-list for you.

The project source code is attached with the tutorial, download the Eclipse Project from there.

Attachment Size – Android Todo App Project 1.11 MB
How to check the version of MySQL database using Python?A Simple Quiz Game in Android
  • vin

    after deleting a few items, the value of an item’s id stored in the database and the value of its position in the list are different. How do I get the common value?

    • Manpreet Vohra

      Let’s say you have Delete button for each TODO list item that user would use to delete a particular TODO item. Now you can set the tag of button to the ID of the question as the list is drawn on the screen. So when the user taps on the Delete button, you can get its Tag and then use it to delete the TODO record with that id.

      e.g. sudo code : delete from task where id = Tag of the particular Delete Button that was pressed.

      In this way the index of the item in the TODO list and actual database ID of the record does not get out of sync.

    • vin

      i figured it out.

      String task_column_id = String.valueOf( list.get(position).getId() );

      this returns the column id of the selected task.

  • scemodicecosa

    How to refresh list after delete an item??
    I use this for delete an item from db but the list change only after I close and reopen the app.

    listTask.setOnItemLongClickListener(new OnItemLongClickListener() {


    public boolean onItemLongClick(AdapterView parent, View view,

    int position, long id) {

    int task = list.get(position).getId();


    // TODO Auto-generated method stub

    return false;

    Great works for the tutorial!

Like us on Facebook