Android编程:通过复选框从listview中查找数据库密钥id。待办事项清单/杂货清单
我是一个使用Android/Java编程的初学者,我在不太难完成的事情上遇到了麻烦。我使用的代码是我试图从谷歌记事本v1中改编的。我意识到这个版本远未完成,但它是最精简的开始 我试图做的是修改列表,使其包含注释,但使其功能类似于待办事项列表,可以向列表中添加项目。在每个项目旁边,都需要有一个复选框。我正在将复选框状态写入数据库,而我遇到的问题是从数据库中收集每个复选框的相关id。如果我手动指定列表中需要的项目,它可以工作,但是我无法获得OnClick(setChk)来提取数据库所需的id。我在下面发布了4个重要的代码文件 我在尝试实现这一点时遇到了很多问题,在编程的这一点上,我只是在创造一些东西来获得编程技能。如果有人有我所描述的功能正常的待办事项列表,我将非常感谢看到一个工作的示例代码。我非常感谢任何帮助 Finished.javaAndroid编程:通过复选框从listview中查找数据库密钥id。待办事项清单/杂货清单,android,sqlite,listview,checkbox,onclick,Android,Sqlite,Listview,Checkbox,Onclick,我是一个使用Android/Java编程的初学者,我在不太难完成的事情上遇到了麻烦。我使用的代码是我试图从谷歌记事本v1中改编的。我意识到这个版本远未完成,但它是最精简的开始 我试图做的是修改列表,使其包含注释,但使其功能类似于待办事项列表,可以向列表中添加项目。在每个项目旁边,都需要有一个复选框。我正在将复选框状态写入数据库,而我遇到的问题是从数据库中收集每个复选框的相关id。如果我手动指定列表中需要的项目,它可以工作,但是我无法获得OnClick(setChk)来提取数据库所需的id。我在下
notes_row.xml
新的完成。爪哇
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);
}
Logcat
03-11 10:38:53.486:E/AndroidRuntime(5611):致命异常:main
03-11 10:38:53.486:E/AndroidRuntime(5611):java.lang.NullPointerException
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.widget.AdapterView.getPositionForView(AdapterView.java:581)
03-11 10:38:53.486:E/AndroidRuntime(5611):在com.finished.finished$1.onCheckedChanged(finished.java:167)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.widget.CompoundButton.setChecked(CompoundButton.java:124)
03-11 10:38:53.486:E/AndroidRuntime(5611):在com.finished.finished$1.setViewValue(finished.java:162)
03-11 10:38:53.486:E/AndroidRuntime(5611):位于android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:126)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.widget.CursorAdapter.getView(CursorAdapter.java:186)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.widget.AbsListView.obtainView(AbsListView.java:1409)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.widget.ListView.makeAndAddView(ListView.java:1745)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.widget.ListView.fillUp(ListView.java:700)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.widget.ListView.correctTooHigh(ListView.java:1367)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.widget.ListView.fillGap(ListView.java:642)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.widget.AbsListView.trackMotionScroll(AbsListView.java:3399)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.widget.AbsListView.onTouchEvent(AbsListView.java:2233)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.widget.ListView.onTouchEvent(ListView.java:3446)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.view.view.dispatchTouchEvent(view.java:3885)上
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:903)上
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)上
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)上
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)上
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)上
03-11 10:38:53.486:E/AndroidRuntime(5611):在com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1691)
03-11 10:38:53.486:E/AndroidRuntime(5611):在com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1125)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.app.Activity.dispatchTouchEvent(Activity.java:2096)上
03-11 10:38:53.486:E/AndroidRuntime(5611):在com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1675)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2194)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.view.ViewRoot.handleMessage(ViewRoot.java:1878)
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.os.Handler.dispatchMessage(Handler.java:99)上
03-11 10:38:53.486:E/AndroidRuntime(5611):在android.os.Looper.loop(Looper.java:123)
03-11 10:38:53.486:E/AndroidRuntime(5611):位于android.app.ActivityThread.main(ActivityThread.java:3683)
03-11 10:38:53.486:E/AndroidRuntime(5611):位于java.lang.reflect.Method.Invokenactive(本机方法)
03-11 10:38:53.486:E/AndroidRuntime(5611):在java.lang.reflect.Method.invoke(Method.java:507)
03-11 10:38:53.486:E/AndroidRuntime(5611):在com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
03-11 10:38:53.486:E/AndroidRuntime(5611):位于com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
03-11 10:38:53.486:E/AndroidRuntime(5611):在dalvik.system.NativeStart.main(本机方法)首先将
SimpleCursorAdapter
作为类的实例变量。然后将setChk更改为以下内容
public void setChk(View view) {
int position = getListView().getPositionForView(view);
Cursor c = notes.getCursor();
if (c.moveToPosition(position)) {
int rowid = c.getInt(c.getColumnIndex(NotesDbAdapter.KEY_ROWID)
//your code
}
}
在您的情况下,OnClickListener
不是最佳选择。单击复选框时,OnCheckedChangeListener
更好。它还有一个优点,即您不必再次调用fillData()
方法,如果数据库很大,这可能需要一些时间
编辑:
我修改了ViewBinder的代码,以便在CheckedChangeListener上使用:
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) {
//TODO update db
} else {
//TODO update db
}
}
}
return true;
}
return false;
}
});
谢谢你,先生!这很有效,我现在已经把一切都准备好了,但是。。。就像你说的,听着
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) > 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) > 0;
}
}
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);
}
public void setChk(View view) {
int position = getListView().getPositionForView(view);
Cursor c = notes.getCursor();
if (c.moveToPosition(position)) {
int rowid = c.getInt(c.getColumnIndex(NotesDbAdapter.KEY_ROWID)
//your code
}
}
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) {
//TODO update db
} else {
//TODO update db
}
}
}
return true;
}
return false;
}
});