title: SQLite Database for Android app force closing
body: <p>I'm working on a ToDo list app to learn more about the Android app development process. I'm following an online tutorial, but I seem to be hitting an error with the SQLite Database stuff. It compiles fine, but it force closes as soon as it is run. Here is the logcat output:</p>
  
  <pre><code>I/SQLiteConnectionPool(24686): The connection pool for /data/data/com.rohan.todo/databases/taskerManager has been closed but there are still 1 connections in use.  They will be closed as they are released back to the pool.
  D/AndroidRuntime(24686): Shutting down VM
  W/dalvikvm(24686): threadid=1: thread exiting with uncaught exception (group=0x410e3930)
  E/AndroidRuntime(24686): FATAL EXCEPTION: main
  E/AndroidRuntime(24686): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.rohan.todo/com.rohan.todo.ViewTask}: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.rohan.todo/databases/taskerManager
  E/AndroidRuntime(24686):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2306)
  E/AndroidRuntime(24686):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2356)
  E/AndroidRuntime(24686):    at android.app.ActivityThread.access$600(ActivityThread.java:150)
  E/AndroidRuntime(24686):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1244)
  E/AndroidRuntime(24686):    at android.os.Handler.dispatchMessage(Handler.java:99)
  E/AndroidRuntime(24686):    at android.os.Looper.loop(Looper.java:137)
  E/AndroidRuntime(24686):    at android.app.ActivityThread.main(ActivityThread.java:5195)
  E/AndroidRuntime(24686):    at java.lang.reflect.Method.invokeNative(Native Method)
  E/AndroidRuntime(24686):    at java.lang.reflect.Method.invoke(Method.java:511)
  E/AndroidRuntime(24686):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
  E/AndroidRuntime(24686):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562)
  E/AndroidRuntime(24686):    at dalvik.system.NativeStart.main(Native Method)
  E/AndroidRuntime(24686): Caused by: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.rohan.todo/databases/taskerManager
  E/AndroidRuntime(24686):    at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
  E/AndroidRuntime(24686):    at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:520)
  E/AndroidRuntime(24686):    at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:263)
  E/AndroidRuntime(24686):    at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
  E/AndroidRuntime(24686):    at com.rohan.todo.TaskerDbHelper.getAllTasks(TaskerDbHelper.java:70)
  E/AndroidRuntime(24686):    at com.rohan.todo.ViewTask.onCreate(ViewTask.java:32)
  E/AndroidRuntime(24686):    at android.app.Activity.performCreate(Activity.java:5104)
  E/AndroidRuntime(24686):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
  E/AndroidRuntime(24686):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2260)
  E/AndroidRuntime(24686):    ... 11 more
  </code></pre>
  
  <p>Here is my code:</p>
  
  <p>ViewTask.java</p>
  
  <pre><code>package com.rohan.todo;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import android.os.Bundle;
  import android.app.Activity;
  import android.content.Context;
  import android.database.sqlite.SQLiteDatabase;
  import android.util.Log;
  import android.view.LayoutInflater;
  import android.view.Menu;
  import android.view.View;
  import android.view.ViewGroup;
  import android.widget.ArrayAdapter;
  import android.widget.CheckBox;
  import android.widget.EditText;
  import android.widget.ListView;
  import android.widget.TextView;
  import android.widget.Toast;
  
  public class ViewTask extends Activity {
      protected TaskerDbHelper db;
      List&lt;Task&gt; list;
      MyAdapter adapt;
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_view_task);
          db = new TaskerDbHelper(this);
          list = db.getAllTasks();
          adapt = new MyAdapter(this, R.layout.list_inner_view, list);
          ListView listTask = (ListView) findViewById(R.id.listView1);
          listTask.setAdapter(adapt);
      }
  
      public void addTaskNow(View v) {
          EditText t = (EditText) findViewById(R.id.editText1);
          String s = t.getText().toString();
          if (s.equalsIgnoreCase("")) {
              Toast.makeText(this, "enter the task description first!!",
                      Toast.LENGTH_LONG);
          } else {
              Task task = new Task(s, 0);
              db.addTask(task);
              Log.d("tasker", "data added");
              t.setText("");
              adapt.add(task);
              adapt.notifyDataSetChanged();
          }
  
      }
  
      @Override
      public boolean onCreateOptionsMenu(Menu menu) {
          // Inflate the menu; this adds items to the action bar if it is present.
          getMenuInflater().inflate(R.menu.activity_view_task, menu);
          return true;
      }
  
      private class MyAdapter extends ArrayAdapter&lt;Task&gt; {
  
          Context context;
          List&lt;Task&gt; taskList = new ArrayList&lt;Task&gt;();
          int layoutResourceId;
  
          public MyAdapter(Context context, int layoutResourceId,
                  List&lt;Task&gt; objects) {
              super(context, layoutResourceId, objects);
              this.layoutResourceId = layoutResourceId;
              this.taskList = objects;
              this.context = context;
          }
  
          /**
           * 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
           */
          @Override
          public View getView(int position, View convertView, ViewGroup parent) {
              CheckBox chk = null;
              if (convertView == null) {
                  LayoutInflater inflater = (LayoutInflater) context
                          .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                  convertView = inflater.inflate(R.layout.list_inner_view,
                          parent, false);
                  chk = (CheckBox) convertView.findViewById(R.id.chkStatus);
                  convertView.setTag(chk);
  
                  chk.setOnClickListener(new View.OnClickListener() {
  
                      @Override
                      public void onClick(View v) {
                          CheckBox cb = (CheckBox) v;
                          Task changeTask = (Task) cb.getTag();
                          changeTask.setStatus(cb.isChecked() == true ? 1 : 0);
                          db.updateTask(changeTask);
                          Toast.makeText(
                                  getApplicationContext(),
                                  "Clicked on Checkbox: " + cb.getText() + " is "
                                          + cb.isChecked(), Toast.LENGTH_LONG)
                                  .show();
                      }
  
                  });
              } else {
                  chk = (CheckBox) convertView.getTag();
              }
              Task current = taskList.get(position);
              chk.setText(current.getTaskName());
              chk.setChecked(current.getStatus() == 1 ? true : false);
              chk.setTag(current);
              Log.d("listener", String.valueOf(current.getId()));
              return convertView;
          }
  
      }
  
  }
  </code></pre>
  
  <p>Task.java</p>
  
  <pre><code>package com.rohan.todo;
  
  public class Task {
      private String taskName;
      private int status;
      private int id;
  
      public Task()
      {
          this.taskName=null;
          this.status=0;
      }
      public Task(String taskName, int status) {
          super();
          this.taskName = taskName;
          this.status = status;
      }
  
      public int getId() {
          return id;
      }
      public void setId(int id) {
          this.id = id;
      }
      public String getTaskName() {
          return taskName;
      }
      public void setTaskName(String taskName) {
          this.taskName = taskName;
      }
      public int getStatus() {
          return status;
      }
      public void setStatus(int status) {
          this.status = status;
      }
  
  }
  </code></pre>
  
  <p>TaskDBHelper.java</p>
  
  <pre><code>package com.rohan.todo;
  
  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.SQLiteDatabase.CursorFactory;
  import android.database.sqlite.SQLiteOpenHelper;
  
  public class TaskerDbHelper extends SQLiteOpenHelper {
  
      private static final int DATABASE_VERSION = 1;
  
      // Database Name
      private static final String DATABASE_NAME = "taskerManager";
  
      // tasks table name
      private static final String TABLE_TASKS = "tasks";
  
      // tasks Table Columns names
      private static final String KEY_ID = "id";
      private static final String KEY_TASKNAME = "taskName";
      private static final String KEY_STATUS = "status";
  
      public TaskerDbHelper(Context context) {
          super(context, DATABASE_NAME, null, DATABASE_VERSION);
      }
  
      @Override
      public void onCreate(SQLiteDatabase db) {
  
          String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_TASKS + " ( "
                  + KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + KEY_TASKNAME
                  + " TEXT, " + KEY_STATUS + " INTEGER)";
          db.execSQL(sql);
  
          db.close();
      }
  
      @Override
      public void onUpgrade(SQLiteDatabase db, int oldV, int newV) {
          // Drop older table if existed
          db.execSQL("DROP TABLE IF EXISTS " + TABLE_TASKS);
          // Create tables again
          onCreate(db);
      }
  
      // Adding new task
      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
      }
  
      public List&lt;Task&gt; getAllTasks() {
          List&lt;Task&gt; taskList = new ArrayList&lt;Task&gt;();
          // 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();
                  task.setId(cursor.getInt(0));
                  task.setTaskName(cursor.getString(1));
                  task.setStatus(cursor.getInt(2));
                  // Adding contact to list
                  taskList.add(task);
              } while (cursor.moveToNext());
          }
  
          // return task list
          return taskList;
      }
  
      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())});
          db.close();
      }
  }
  </code></pre>
  
  <p>If someone could help me find the error in the code and suggest a fix, I'd greatly appreciate it! Thank you very much in advance for helping a noob like me :)</p>