First steps on Android: Creating a simple Todo App
April 26th, 2010 by Micha KopsIn this tutorial we are going to build a simple todo app that is able to store simple todos in a database. The user is able to add new todos or delete old ones by clicking on a todo. For this tutorial we won’t use maven to keep it simple – if maven integration is desired – take a look at this tutorial.
Contents
Steps
- Create a new android project using the Android SDK and your IDE
- Create some packages com.hascode.android.activity and com.hascode.android.persistence
- Create the layout in res/layout/main.xml – the main elements: a listview for the todos-list, a textbox and a button to enter new data.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/widget31" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" > <TableRow android:id="@+id/row" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_below="@+id/tasklist" android:layout_alignParentLeft="true" > <EditText android:id="@+id/etNewTask" android:layout_width="200px" android:layout_height="wrap_content" android:text="" android:textSize="18sp" > </EditText> <Button android:id="@+id/btNewTask" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@+string/add_button_name" > </Button> </TableRow> <ListView android:id="@+id/tasklist" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" > </ListView> </RelativeLayout>
- Externalize strings in the strings.xml - e.g. the button text or the application’s name
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">SimpleTodos</string> <string name="add_button_name">Add new todo</string> </resources>
- Create a new activity in com.hascode.android.activity named SimpleTodoActivity. Logging activity is mapped at the defined Tag in APP_TAG.
package com.hascode.android.activity; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; import com.hascode.android.R; import com.hascode.android.persistence.TaskProvider; public class SimpleTodoActivity extends Activity { public static final String APP_TAG = "com.hascode.android.simple-todos"; private ListView taskView; private Button btNewTask; private EditText etNewTask; private TaskProvider provider; /* * (non-Javadoc) * * @see android.app.Activity#onCreate(android.os.Bundle) */ @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.main); provider = new TaskProvider(this); taskView = (ListView) findViewById(R.id.tasklist); btNewTask = (Button) findViewById(R.id.btNewTask); etNewTask = (EditText) findViewById(R.id.etNewTask); btNewTask.setOnClickListener(handleNewTaskEvent); renderTodos(); } /** * renders the task list */ private void renderTodos() { } }
- Create the event handling for the button and add the following Listener to the class:
private OnClickListener handleNewTaskEvent = new OnClickListener() { @Override public void onClick(View view) { Log.d(APP_TAG, "add task click received"); provider.addTask(etNewTask.getText().toString()); renderTodos(); } };
- Create an adapter class for database access in com.hascode.android.persistence named TodoProvider with methods for creating/deletion of database entries .. please note that the iterator cursor.next() does not exist anymore in the Cursor class .. new api .. new luck …
package com.hascode.android.persistence; 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; import android.util.Log; import com.hascode.android.activity.SimpleTodoActivity; public class TodoProvider { private static final String DB_NAME = "tasks"; private static final String TABLE_NAME = "tasks"; private static final int DB_VERSION = 1; private static final String DB_CREATE_QUERY = "CREATE TABLE " + TABLE_NAME + " (id integer primary key autoincrement, title text not null);"; private SQLiteDatabase storage; private SQLiteOpenHelper helper; public TodoProvider(Context ctx) { helper = new SQLiteOpenHelper(ctx, DB_NAME, null, DB_VERSION) { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); onCreate(db); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(DB_CREATE_QUERY); } }; storage = helper.getWritableDatabase(); } public List<String> findAll() { Log.d(SimpleTodoActivity.APP_TAG, "findAll triggered"); List<String> tasks = new ArrayList<String>(); Cursor c = storage.query(TABLE_NAME, new String[] { "title" }, null, null, null, null, null); if (c != null) { c.moveToFirst(); while (c.isAfterLast() == false) { tasks.add(c.getString(0)); c.moveToNext(); } c.close(); } return tasks; } public void addTask(String title) { ContentValues data = new ContentValues(); data.put("title", title); storage.insert(TABLE_NAME, null, data); } public void deleteTask(String title) { storage.delete(TABLE_NAME, "title='" + title + "'", null); } public void deleteTask(long id) { storage.delete(TABLE_NAME, "id=" + id, null); } }
- Connect the activity to the database – implement renderTodos in the Activity and add an event listener for clicks on the list items. Adapters do the job of adding items to the listview. Please do not use setClickListener for the ListView – use setOnItemClickListener instead!
/** * renders the task list */ private void renderTodos() { List<String> todos = provider.findAll(); if (!todos.isEmpty()) { Log.d(APP_TAG, String.format("%d beans found", beans.size())); // render the list taskView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, todos .toArray(new String[] {}))); // dumb item deletion onclick taskView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Log.d(APP_TAG, String.format( "item with id: %d and position: %d", id, position)); TextView v = (TextView) view; provider.deleteTask(v.getText().toString()); renderTodos(); } }); } else { Log.d(APP_TAG, "no tasks found"); } }
- Sign your app as described in this article and deploy it if you wish to test it on your phone – currently I am using the new HTC Desire :) .If you’re using Eclipse and the Android Tools for Eclipse: Project > Android Tools > Export Signed Application Package
- Finally the app looks like this on my emulator:
Source download
- You’re able to fetch the source code from this tutorial from Bitbucket
- Alternatively if you have got Mercurial installed, just clone the repository using the following command
hg clone http://bitbucket.org/hascode/android-simple-tasks
Troubleshooting
- Examining the database with the Android Debugging Bridge – first list your connected devices:
>> adb devices List of devices attached emulator-5554 device
- Connect to your device:
adb -s emulator-5554 shell
- Connect to the database .. the path is /data/data/<your-app-package-name>/<your-database-name>.db
# sqlite3 /data/data/com.hascode.android/databases/tasks.db SQLite version 3.5.9 Enter ".help" for instructions
- Look what you’ve got: Use the commands .databases and .tables to receive information about existing databases and tables
sqlite> .databases seq name file --- --------------- ---------------------------------------------------------- 0 main /data/data/com.hascode.android/databases/tasks.db
- View detailed log information via logcat in the ADB console – you should define a filter to avoid information overflow
# logcat W/ActivityManager( 51): Launch timeout has expired, giving up wake lock! W/ActivityManager( 51): Activity idle timeout for HistoryRecord{43d60f08 com.hascode.android/.activity.SimpleTaskActivity} D/dalvikvm( 51): GC freed 12535 objects / 605968 bytes in 128ms I/Process ( 204): Sending signal. PID: 204 SIG: 9 I/ActivityManager( 51): Process com.hascode.android (pid 204) has died. I/UsageStats( 51): Unexpected resume of com.android.launcher while already resumed in com.hascode.android D/com.hascode.android.simple-task( 182): item with id: 3 and position: 3 clicked D/com.hascode.android.simple-task( 182): item with id: 2 and position: 2 clicked D/com.hascode.android.simple-task( 182): item with id: 1 and position: 1 clicked D/com.hascode.android.simple-task( 182): item with id: 1 and position: 1 clicked
Resources
- Android Homepage
- DroidDraw Homepage
- Maven and Android Integration
- Android Developers: Notepad Tutorial
- Android Developers: Data Storage
- ScreamingPenguin.com: Android SQLite Basics
- Android Developers: ADB Commands
- Bestsiteinthemultiverse.com: Android Selected State ListView Examples
- Android Developers: Common Tasks and How to do them in Android
- Android Developers: Android SDK
- Android Developers: Signing your application
Tags: activity, adb, Android, example, htc desire, logging, mobile, sqlite, tutorial
October 26th, 2010 at 9:30 am
i am gettin error in SimpleTodoActivity class can u brief me thge complete code r can u just gimme the complete code
October 31st, 2010 at 9:02 pm
Sure! I have put my source code on bitbucket.org – just download from https://bitbucket.org/hascode/hascode-tutorials/src/tip/SimpleTasks/ or clone the repository using hg clone http://bitbucket.org/hascode/hascode-tutorials
Hope this helps :)
March 3rd, 2011 at 3:37 pm
Hi, i am getting error in SimpleTodoActivity class, i found the error in this line
“import com.hascode.android.R;”
the error sounds :
The import com.hascode.android.R cannot be resolved
can u explain me, how to fix the error?
Thank you :D
March 3rd, 2011 at 3:44 pm
Hi, I am getting error in SimpleTodoActivity class
- The import com.hascode.android.R cannot be resolved
Would you like to give some advices? Thank you for your help and response. =)
March 19th, 2011 at 1:48 pm
Hi,
this file is automatically generated by one of the ADT builders .. please check if you’ve got a valid installation of the Android Eclipse ADT plugin.
April 26th, 2011 at 6:25 am
nice tutorial
December 19th, 2011 at 10:36 am
new repository location: https://bitbucket.org/hascode/android-simple-tasks