title: Android Programming: Find the database key id from listview with checkbox. To do list / grocery list
body: <p>I am a beginner when it comes to programming with Android/Java, and I am having trouble with what shouldn't be too difficult to accomplish. I am using code I've tried to adapt from the Google Notepad v1. I realize this version is far from complete, but it was the most stripped down to begin on. </p>
  
  <p>What I am trying to do is modify the list to note include notes, but rather make it function like a to-do list, where one would add items to the list. Next to each item, there needs to be a checkbox. I'm writing the checkbox state to the database, and where I am having trouble is gathering the related id from the database for each checkbox. If I manually specify which item I want in the list it works, but I'm unable to get OnClick (setChk) to pull the id I need for the database. I am posting 4 important code files below. </p>
  
  <p>I have had so many problems trying to get this to work, and at this point in programming, I'm just creating things to gain programming skills. If anyone has a functioning to-do list as I've described, I would greatly appreciate seeing a working sample code. I greatly appreciate any help!</p>
  
  <p>Finished.java</p>
  
  <hr>
  
  <pre><code>import android.app.ListActivity;
  import android.database.Cursor;
  import android.os.Bundle;
  import android.view.Menu;
  import android.view.MenuItem;
  import android.view.View;
  import android.widget.CheckBox;
  import android.widget.SimpleCursorAdapter;
  import android.widget.Toast;
  
  public class Finished extends ListActivity {
  
  
      public static final int INSERT_ID = Menu.FIRST;
  
      private int mNoteNumber = 1;
      private NotesDbAdapter mDbHelper;
  
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.notepad_list);
  
  
  
  
      mDbHelper = new NotesDbAdapter(this);
      mDbHelper.open();
  
      fillData(); 
  }
  
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
      boolean result = super.onCreateOptionsMenu(menu);
      menu.add(0, INSERT_ID, 0, R.string.menu_insert);
      return result;
  }
  
  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
      switch (item.getItemId()) {
      case INSERT_ID:
          createNote();
          return true;
      }
      return super.onOptionsItemSelected(item);
  }
  
  
  private void createNote() {
      String noteName = "Note " + mNoteNumber++;
      mDbHelper.createNote(noteName, "", "1");
      fillData();
  }
  
  private void fillData() {
      Cursor c = mDbHelper.fetchAllNotes();
      startManagingCursor(c);
  
      String[] from = new String[] { NotesDbAdapter.KEY_TITLE, NotesDbAdapter.KEY_CHECK };
      int[] to = new int[] { R.id.text1, R.id.CheckBox1 };
  
      // Now create an array adapter and set it to display using our row
      SimpleCursorAdapter notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
  
  
  
      notes.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
        public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
          int nCheckedIndex = cursor.getColumnIndexOrThrow(NotesDbAdapter.KEY_CHECK);
          if (columnIndex == nCheckedIndex) {
            CheckBox cb = (CheckBox) view;
  
            boolean bChecked = (cursor.getInt(nCheckedIndex) != 0);
            cb.setChecked(bChecked);
            return true;
          }
  
          return false;
  
  
          }
  
      });
  
  
      setListAdapter(notes);
  
    }
  
  public void setChk(View view) {
  
      //Below is where I need help
      mDbHelper.updateChk(//insert proper number id in list to delete, "1");
      //I understand I don't want second value to be 1. It was also just a test
      //I need to work on getting the id first before anything else
      Toast.makeText(this, "Selected", Toast.LENGTH_SHORT).show();
  
      fillData();
  
  }
  
  }
  </code></pre>
  
  <hr>
  
  <p>notes_row.xml</p>
  
  <hr>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"      
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" &gt;
  
  &lt;TextView 
  android:id="@+id/text1" 
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" 
  android:layout_alignParentTop="true"
  android:layout_alignParentLeft="true"&gt;
  &lt;/TextView&gt;
  
  &lt;CheckBox 
  android:id="@+id/CheckBox1" 
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" 
  android:layout_alignParentTop="true" 
  android:layout_alignParentRight="true"
  android:onClick="setChk"
  android:text="setChk"&gt;
  &lt;/CheckBox&gt;
  &lt;/RelativeLayout&gt;
  </code></pre>
  
  <hr>
  
  <p>notepad_list.xml</p>
  
  <hr>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
  android:layout_height="wrap_content"&gt;
  
  &lt;ListView android:id="@id/android:list"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"/&gt;
  &lt;TextView android:id="@id/android:empty"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="@string/no_notes"/&gt;
  
      &lt;/LinearLayout&gt;
  </code></pre>
  
  <hr>
  
  <p>NotesDbAdapter</p>
  
  <hr>
  
  <pre><code>    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 NotesDbAdapter {
  
  public static final String KEY_TITLE = "title";
  public static final String KEY_BODY = "body";
  public static final String KEY_ROWID = "_id";
  public static final String KEY_CHECK = "check";
  
  private static final String TAG = "NotesDbAdapter";
  private DatabaseHelper mDbHelper;
  private SQLiteDatabase mDb;
  
  /**
   * Database creation sql statement
   */
  private static final String DATABASE_CREATE =
      "create table notes (_id integer primary key autoincrement, "
      + "title text not null, body text not null);";
  
  private static final String DATABASE_NAME = "data";
  private static final String DATABASE_TABLE = "notes";
  private static final int DATABASE_VERSION = 3;
  
  
  private final Context mCtx;
  
  private static class DatabaseHelper extends SQLiteOpenHelper {
  
      DatabaseHelper(Context context) {
          super(context, DATABASE_NAME, null, DATABASE_VERSION);
      }
  
      @Override
      public void onCreate(SQLiteDatabase db) {
  
          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 notes");
          onCreate(db);
      }
  }
  
  /**
   * Constructor - takes the context to allow the database to be
   * opened/created
   * 
   * @param ctx the Context within which to work
   */
  public NotesDbAdapter(Context ctx) {
      this.mCtx = ctx;
  }
  
  /**
   * Open the notes database. If it cannot be opened, try to create a new
   * instance of the database. If it cannot be created, throw an exception to
   * signal the failure
   * 
   * @return this (self reference, allowing this to be chained in an
   *         initialization call)
   * @throws SQLException if the database could be neither opened or created
   */
  public NotesDbAdapter open() throws SQLException {
      mDbHelper = new DatabaseHelper(mCtx);
      mDb = mDbHelper.getWritableDatabase();
      return this;
  }
  
  public void close() {
      mDbHelper.close();
  }
  
  
  /**
   * Create a new note using the title and body provided. If the note is
   * successfully created return the new rowId for that note, otherwise return
   * a -1 to indicate failure.
   * 
   * @param title the title of the note
   * @param body the body of the note
   * @return rowId or -1 if failed
   */
  public long createNote(String title, String body, String check) {
      ContentValues initialValues = new ContentValues();
      initialValues.put(KEY_TITLE, title);
      initialValues.put(KEY_BODY, body);
      initialValues.put(KEY_BODY, check);
  
      return mDb.insert(DATABASE_TABLE, null, initialValues);
  }
  
  /**
   * Delete the note with the given rowId
   * 
   * @param rowId id of note to delete
   * @return true if deleted, false otherwise
   */
  public boolean deleteNote(long rowId) {
  
      return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) &gt; 0;
  }
  
  /**
   * Return a Cursor over the list of all notes in the database
   * 
   * @return Cursor over all notes
   */
  public Cursor fetchAllNotes() {
  
      return mDb.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_TITLE,
              KEY_BODY, KEY_CHECK}, null, null, null, null, null, null);
  }
  
  /**
   * Return a Cursor positioned at the note that matches the given rowId
   * 
   * @param rowId id of note to retrieve
   * @return Cursor positioned to matching note, if found
   * @throws SQLException if note could not be found/retrieved
   */
  public Cursor fetchNote(long rowId) throws SQLException {
  
      Cursor mCursor =
  
          mDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID,
                  KEY_TITLE, KEY_BODY, KEY_CHECK}, KEY_ROWID + "=" + rowId, null,
                  null, null, null, null);
      if (mCursor != null) {
          mCursor.moveToFirst();
      }
      return mCursor;
  
  }
  
  /**
   * Update the note using the details provided. The note to be updated is
   * specified using the rowId, and it is altered to use the title and body
   * values passed in
   * 
   * @param rowId id of note to update
   * @param title value to set note title to
   * @param body value to set note body to
   * @param check 
   * @return true if the note was successfully updated, false otherwise
   */
  public boolean updateNote(long rowId, String title, String body, String check) {
      ContentValues args = new ContentValues();
      args.put(KEY_TITLE, title);
      args.put(KEY_BODY, body);
      args.put(KEY_CHECK, check);
  
      return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) &gt; 0;
  }
  }
  </code></pre>
  
  <p>New Finished. java</p>
  
  <pre><code>private void fillData() {
      Cursor c = mDbHelper.fetchAllNotes();
      startManagingCursor(c);
  
      String[] from = new String[] { NotesDbAdapter.KEY_TITLE, NotesDbAdapter.KEY_CHECK };
      int[] to = new int[] { R.id.text1, R.id.CheckBox1 };
  
      // Now create an array adapter and set it to display using our row
      final SimpleCursorAdapter notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
  
  
  
      notes.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
          public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
              int nCheckedIndex = cursor.getColumnIndexOrThrow(NotesDbAdapter.KEY_CHECK);
              if (columnIndex == nCheckedIndex) {
                  CheckBox cb = (CheckBox) view;
  
                  boolean bChecked = (cursor.getInt(nCheckedIndex) != 0);
                  cb.setChecked(bChecked);
  
                  //call if after setChecked so the listener isn't called there already
                  cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                      public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                          int position = getListView().getPositionForView(buttonView);
                          Cursor c = notes.getCursor();
                          if (c.moveToPosition(position)) {
  
                              int rowid = c.getInt(c.getColumnIndex(NotesDbAdapter.KEY_ROWID));
  
                              if (isChecked) {
                                  mDbHelper.updateChk(rowid, "1");
  
  
                              } else {
                                  mDbHelper.updateChk(rowid, "0");
  
                              }
  
  
                          } 
                      }
  
              });
                  return true;
              }
              return false;
          }
      });
  
  
      setListAdapter(notes);
  
    }
  </code></pre>
  
  <p>Logcat</p>
  
  <p>03-11 10:38:53.486: E/AndroidRuntime(5611): FATAL EXCEPTION: main
  03-11 10:38:53.486: E/AndroidRuntime(5611): java.lang.NullPointerException
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.widget.AdapterView.getPositionForView(AdapterView.java:581)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at com.finished.Finished$1$1.onCheckedChanged(Finished.java:167)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.widget.CompoundButton.setChecked(CompoundButton.java:124)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at com.finished.Finished$1.setViewValue(Finished.java:162)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:126)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.widget.CursorAdapter.getView(CursorAdapter.java:186)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.widget.AbsListView.obtainView(AbsListView.java:1409)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.widget.ListView.makeAndAddView(ListView.java:1745)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.widget.ListView.fillUp(ListView.java:700)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.widget.ListView.correctTooHigh(ListView.java:1367)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.widget.ListView.fillGap(ListView.java:642)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.widget.AbsListView.trackMotionScroll(AbsListView.java:3399)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.widget.AbsListView.onTouchEvent(AbsListView.java:2233)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.widget.ListView.onTouchEvent(ListView.java:3446)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.view.View.dispatchTouchEvent(View.java:3885)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:903)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1691)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1125)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.app.Activity.dispatchTouchEvent(Activity.java:2096)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1675)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2194)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1878)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.os.Handler.dispatchMessage(Handler.java:99)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.os.Looper.loop(Looper.java:123)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at android.app.ActivityThread.main(ActivityThread.java:3683)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at java.lang.reflect.Method.invokeNative(Native Method)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at java.lang.reflect.Method.invoke(Method.java:507)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
  03-11 10:38:53.486: E/AndroidRuntime(5611):     at dalvik.system.NativeStart.main(Native Method)</p>