与此处的其他几篇文章一样,我正在尝试创建一个ListView,其中包含每行的CheckBox,并使用sqlite数据库存储选择的当前状态.
从http://appfulcrum.com/?p=351的示例开始,这个示例并不完全正常,我创建了一个创建数据库的简单应用程序,用20个项目填充它,并显示列表.
它成功检索状态并存储选择的状态.
但是,如果我更改它,它无法正确显示CheckBox状态,滚动到列表的另一端,然后向后滚动.例如如果我选择第一个CheckBox,滚动到底部,然后回到顶部,不再设置CheckBox.这是在Android 2.1三星手机上运行.
如果我返回主屏幕,返回列表,CheckBox已正确设置,因此数据库确实已更新.
该示例扩展了SimpleCursorAdapter,并且getView()根据表中选择列的值,根据需要使用true或false调用setChecked().
以下是所有来源.
我当然很感激被告知,“呃,这是你的问题……”
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<Void,Void,String> {
- 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,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 < 20-count; i++) {
- db.execsql("INSERT INTO ToDoItems VALUES(NULL,'Task #"+i+"','Description #"+i+"',0);");
- }
- }
- public void openDataBase() throws sqlException {
- String myPath = DATABASE_PATH + DATABASE_NAME;
- dbsqlite = sqliteDatabase.openDatabase(myPath,sqliteDatabase.OPEN_READWRITE);
- }
- @Override
- public synchronized void close() {
- if (dbsqlite != null)
- dbsqlite.close();
- super.close();
- }
- public Cursor getCursor() {
- sqliteQueryBuilder queryBuilder = new sqliteQueryBuilder();
- queryBuilder.setTables(TABLE_NAME);
- String[] asColumnsToReturn = new String[] { COLUMN_ID,COLUMN_TITLE,COLUMN_NAME_DESC,COLUMN_SELECTED };
- Cursor mCursor = queryBuilder.query(dbsqlite,asColumnsToReturn,COLUMN_ID+" ASC");
- return mCursor;
- }
- public void clearSelections() {
- ContentValues values = new ContentValues();
- values.put(COLUMN_SELECTED,0);
- this.dbsqlite.update(sqlHelper.TABLE_NAME,null);
- }
- }
Start.java
- //src/Start.java
- package com.appfulcrum.blog.examples.listviewcustomdb;
- import android.app.Activity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.Toast;
- public class Start extends Activity {
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Button btnSimple = (Button) findViewById(R.id.btnSimple);
- btnSimple.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- Toast.makeText(getApplicationContext()," You clicked ListView From DB button",Toast.LENGTH_SHORT).show();
- Intent intent = new Intent(v.getContext(),CustomListViewDB.class);
- startActivityForResult(intent,0);
- }
- });
- }
- }
布局/ main.xml中
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/buttonlayout" android:orientation="vertical"
- android:layout_width="fill_parent" android:layout_height="fill_parent"
- android:gravity="left|top" android:paddingTop="2dp"
- android:paddingBottom="2dp">
- <TextView android:id="@+id/txtTest" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:textStyle="bold"
- android:text="@string/app_name" android:textSize="15sp"
- android:textColor="#FF0000" android:gravity="center_vertical"
- android:paddingLeft="5dp">
- </TextView>
- <Button android:id="@+id/btnSimple"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:textSize="15sp"
- android:text="Listview from DB"
- android:textColor="#000000"
- >
- </Button>
- </LinearLayout>
布局/ simple.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical" android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <LinearLayout android:id="@+id/buttonlayout"
- android:orientation="horizontal" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:height="32dp"
- android:gravity="left|top" android:paddingTop="2dp"
- android:paddingBottom="2dp">
- <LinearLayout android:id="@+id/buttonlayout2"
- android:orientation="horizontal" android:layout_height="wrap_content"
- android:gravity="left|center_vertical" android:layout_width="wrap_content"
- android:layout_gravity="left|center_vertical">
- <TextView android:id="@+id/txtTest"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent" android:textStyle="bold"
- android:text="@string/list_header" android:textSize="15sp"
- android:gravity="center_vertical" android:paddingLeft="5dp">
- </TextView>
- <Button android:id="@+id/btnClear"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" android:text="Clear"
- android:textSize="15sp" android:layout_marginLeft="10px"
- android:layout_marginRight="10px"
- android:layout_marginBottom="2px"
- android:layout_marginTop="2px" android:height="15dp"
- android:width="70dp"></Button>
- </LinearLayout>
- </LinearLayout>
- <TableLayout android:id="@+id/TableLayout01"
- android:layout_width="fill_parent" android:layout_height="fill_parent"
- android:stretchColumns="*">
- <TableRow>
- <ListView android:id="@android:id/list"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"></ListView>
- </TableRow>
- </TableLayout>
- </LinearLayout>
布局/ single_item.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent" android:layout_height="wrap_content"
- android:orientation="horizontal" android:gravity="center_vertical">
- <CheckBox android:id="@+id/bcheck"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent" />
- <TextView android:id="@+id/txtTitle"
- android:layout_width="wrap_content" android:gravity="left|center_vertical"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:layout_alignParentLeft="true"
- android:textSize="20sp" android:text="Test"
- android:textStyle="bold" android:paddingLeft="5dp"
- android:paddingRight="2dp" android:focusable="false"
- android:focusableInTouchMode="false"></TextView>
- <LinearLayout android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:orientation="horizontal"
- android:gravity="right|center_vertical">
- </LinearLayout>
- </LinearLayout>
值/ strings.xml中
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <string name="hello">Hello World,ListViewWithDBActivity!</string>
- <string name="app_name">ListViewWithDB</string>
- <string name="list_header">List Headers</string>
- </resources>
AndroidManifest.xml中
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- android:versionCode="1" android:versionName="1.0"
- package="com.appfulcrum.blog.examples.listviewcustomdb">
- <application android:icon="@drawable/icon"
- android:label="@string/app_name"
- android:theme="@android:style/Theme.NoTitleBar">
- >
- <activity android:name=".Start" android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name=".CustomListViewDB"></activity>
- </application>
- <uses-sdk android:minSdkVersion="7" /> <!-- android 1.6 -->
- </manifest>
如果你想构建,将一些任意的icon.png扔进drawable.
提前致谢.