Android: ListView with CheckBox, populated from SQLite database not quite working?

I found the most complete solution to the problem off-site.

Up vote 0 down vote favorite share g+ share fb share tw.

As with several other posts here, I am trying to create a ListView that includes a CheckBox for each row, and use a SQLite database to store the current state of the selection. Starting with the example at appfulcrum.com/?p=351, which did not quite work as is, I created a simple app that creates the database, populates it with 20 items, and displays the list. It successfully retrieves the state and stores the state of the selection.

BUT, it does not correctly show the CheckBox state if I change it, scroll to the other end of the list, and scroll back. E.g. If I select the first CheckBox, scroll to the bottom, and come back to the top, the CheckBox is no longer set.

This is being run on an Android 2.1 Samsung handset. If I return to the main screen, come back into the list, the CheckBox is correctly set, so the database has indeed been updated. The example extends SimpleCursorAdapter, and the getView() invokes setChecked() with true or false as appropriate based on the value of the selection column in the table.

Below are all the sources. I'd certainly appreciate being told, "Duh, here's your problem..." CustomListViewDB. Java // src/CustomListViewDB.

Java package com.appfulcrum.blog.examples. Listviewcustomdb; import android.app. ListActivity; import android.database.

Cursor; import android.database. SQLException; import android.os. AsyncTask; import android.os.

Bundle; import android.view. View; import android.view.View. OnClickListener; import android.widget.

Button; import android.widget. ListView; import android.widget. Toast; public class CustomListViewDB extends ListActivity { private ListView mainListView = null; CustomSqlCursorAdapter adapter = null; private SqlHelper dbHelper = null; private Cursor currentCursor = null; private ListView listView = null; /** Called when the activity is first created.

*/ @Override public void onCreate(Bundle savedInstanceState) { super. OnCreate(savedInstanceState); setContentView(R.layout. Simple); if (this.

DbHelper == null) { this. DbHelper = new SqlHelper(this); } listView = getListView(); listView. SetItemsCanFocus(false); listView.

SetChoiceMode(ListView. CHOICE_MODE_MULTIPLE); //listView. SetClickable(true); Button btnClear = (Button) findViewById(R.id.

BtnClear); btnClear. SetOnClickListener(new OnClickListener() { public void onClick(View v) { Toast. MakeText(getApplicationContext(), " You clicked Clear button", Toast.

LENGTH_SHORT).show(); ClearDBSelections(); } }); new SelectDataTask().execute(); this. MainListView = getListView(); mainListView. SetCacheColorHint(0); } @Override protected void onRestart() { super.onRestart(); new SelectDataTask().execute(); } @Override protected void onPause() { super.onPause(); this.dbHelper.close(); } protected void ClearDBSelections() { this.adapter.ClearSelections(); } private class SelectDataTask extends AsyncTask { protected String doInBackground(Void... params) { try { CustomListViewDB.this.dbHelper.

CreateDatabase(dbHelper. DbSqlite); CustomListViewDB.this.dbHelper.openDataBase(); CustomListViewDB.this. CurrentCursor = CustomListViewDB.this.

DbHelper .getCursor(); } catch (SQLException sqle) { throw sqle; } return null; } // can use UI thread here protected void onPostExecute(final String result) { startManagingCursor(CustomListViewDB.this. CurrentCursor); int listFields = new int { R.id. TxtTitle }; String dbColumns = new String { SqlHelper.

COLUMN_TITLE }; CustomListViewDB.this. Adapter = new CustomSqlCursorAdapter( CustomListViewDB. This, R.layout.

Single_item, CustomListViewDB.this. CurrentCursor, dbColumns, listFields, CustomListViewDB.this. DbHelper); setListAdapter(CustomListViewDB.this.

Adapter); } } } CustomSqlCursorAdapter. Java // src/CustomSqlCursorAdapter. Java package com.appfulcrum.blog.examples.

Listviewcustomdb; import android.content. ContentValues; import android.content. Context; import android.database.

Cursor; import android.database. SQLException; import android.util. Log; import android.view.

LayoutInflater; import android.view. View; import android.view. ViewGroup; import android.widget.

CheckBox; import android.widget. CompoundButton; import android.widget.CompoundButton. OnCheckedChangeListener; import android.widget.

SimpleCursorAdapter; import android.widget. TextView; public class CustomSqlCursorAdapter extends SimpleCursorAdapter { private Context mContext; private SqlHelper mDbHelper; private Cursor mCurrentCursor; public CustomSqlCursorAdapter(Context context, int layout, Cursor c, String from, int to, SqlHelper dbHelper) { super(context, layout, c, from, to); this. MCurrentCursor = c; this.

MContext = context; this. MDbHelper = dbHelper; } public View getView(int pos, View inView, ViewGroup parent) { View v = inView; if (v == null) { LayoutInflater inflater = (LayoutInflater) mContext . GetSystemService(Context.

LAYOUT_INFLATER_SERVICE); v = inflater. Inflate(R.layout. Single_item, null); } if (!this.mCurrentCursor.

MoveToPosition(pos)) { throw new SQLException("CustomSqlCursorAdapter. GetView: Unable to move to position: "+pos); } CheckBox cBox = (CheckBox) v. FindViewById(R.id.

Bcheck); // save the row's _id value in the checkbox's tag for retrieval later cBox. SetTag(Integer. ValueOf(this.mCurrentCursor.

GetInt(0))); if (this.mCurrentCursor. GetInt(SqlHelper. COLUMN_SELECTED_idx)!

= 0) { cBox. SetChecked(true); Log. W("SqlHelper", "CheckBox true for pos "+pos+", id="+this.mCurrentCursor.

GetInt(0)); } else { cBox. SetChecked(false); Log. W("SqlHelper", "CheckBox false for pos "+pos+", id="+this.mCurrentCursor.

GetInt(0)); } //cBox. SetOnClickListener(this); cBox. SetOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { Log.

W("SqlHelper", "Selected a CheckBox and in onCheckedChanged: "+isChecked); Integer _id = (Integer) buttonView.getTag(); ContentValues values = new ContentValues(); values. Put(SqlHelper. COLUMN_SELECTED, isChecked?

Integer. ValueOf(1) : Integer. ValueOf(0)); mDbHelper.dbSqlite.

BeginTransaction(); try { if (mDbHelper.dbSqlite. Update(SqlHelper. TABLE_NAME, values, "_id=?

", new String { Integer. ToString(_id) })! = 1) { throw new SQLException("onCheckedChanged failed to update _id="+_id); } mDbHelper.dbSqlite.

SetTransactionSuccessful(); } finally { mDbHelper.dbSqlite.endTransaction(); } Log. W("SqlHelper", "-- _id="+_id+", isChecked="+isChecked); } }); TextView txtTitle = (TextView) v. FindViewById(R.id.

TxtTitle); txtTitle. SetText(this.mCurrentCursor. GetString(this.

MCurrentCursor . GetColumnIndex(SqlHelper. COLUMN_TITLE))); return (v); } public void ClearSelections() { this.mDbHelper.clearSelections(); this.mCurrentCursor.requery(); } } ListViewWithDBActivity.

Java package com.appfulcrum.blog.examples. Listviewcustomdb; import android.app. Activity; import android.os.

Bundle; public class ListViewWithDBActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super. OnCreate(savedInstanceState); setContentView(R.layout.

Main); } } SqlHelper // SqlHelper. Java package com.appfulcrum.blog.examples. Listviewcustomdb; 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.database.sqlite.

SQLiteQueryBuilder; import android.database.sqlite. SQLiteStatement; import android.util. Log; public class SqlHelper extends SQLiteOpenHelper { private static final String DATABASE_PATH = "/data/data/com.appfulcrum.blog.examples.

Listviewcustomdb/databases/"; public static final String DATABASE_NAME = "TODOList"; public static final String TABLE_NAME = "ToDoItems"; public static final int ToDoItems_VERSION = 1; public static final String COLUMN_ID = "_id"; // 0 public static final String COLUMN_TITLE = "title"; // 1 public static final String COLUMN_NAME_DESC = "description";// 2 public static final String COLUMN_SELECTED = "selected"; // 3 public static final int COLUMN_SELECTED_idx = 3; public SQLiteDatabase dbSqlite; private Context mContext; public SqlHelper(Context context) { super(context, DATABASE_NAME, null, 1); mContext = context; } @Override public void onCreate(SQLiteDatabase db) { createDB(db); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log. W("SqlHelper", "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data"); db. ExecSQL("DROP TABLE IF EXISTS ToDoItems;"); createDB(db); } public void createDatabase(SQLiteDatabase db) { createDB(db); } private void createDB(SQLiteDatabase db) { if (db == null) { db = mContext.

OpenOrCreateDatabase(DATABASE_NAME, 0, null); } db. ExecSQL("CREATE TABLE IF NOT EXISTS ToDoItems (_id INTEGER PRIMARY KEY, title TEXT, " +" description TEXT, selected INTEGER);"); db. SetVersion(ToDoItems_VERSION); // // Generate a few rows for an example // // find out how many rows already exist, and make sure there's some minimum SQLiteStatement s = db.

CompileStatement("select count(*) from ToDoItems;"); long count = s. SimpleQueryForLong(); for (int I = 0; I layout/simple. Xml layout/single_item.

Xml values/strings. Xml ListViewWithDBActivity! ListViewWithDB List Headers AndroidManifest.

Xml > If you want to build, throw some arbitrary icon. Png into drawable. Thanks in advance.

Android sqlite listview checkbox link|improve this question asked Aug 29 '11 at 14:34user877139666.

2 TL;DR... Really, try to be more concise. – Daniel Hilgarth Sep 2 '11 at 9:50 Other questions like this were more concise, but still left people confused. I wanted to provide as much information as needed.

As noted in my additional Answer, another site provided a solution for the exact issue. Cheers. – user877139 Sep 3 '11 at 2:32.

I found the most complete solution to the problem off-site. At Android ListView with CheckBox : Retain State Appreciate the help folks.

The Views in a ListView are recycled, and this sounds like an issue with that. You probably need to invalidate your onCheckedChangedListener so that when you do setChecked() it isn't calling the previous listener inadvertently. There could be other ramifications of the recycling as well, so keep that in mind.

So try: cBox. SetOnCheckedChangeListener(null); ... cBox.setChecked(); ... cBox. SetOnCheckedChangeListner(.

Worth a try. Tried. Didn't change the behavior.

Made sure with debugger that new code was on the device. It feels like it has cached a row of the db that is not flushed until I leave the list. But that's why I added all the transaction code.

– user877139 Aug 29 '11 at 16:04.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions