与此处的其他几篇文章一样,我正在尝试创建一个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.
提前致谢.