如何根据数据库中的信息制作复选框?
How to make a checkbox from information found in DataBase?
我在数据库中有一个 table,我想创建一个 table。
现在,我会做很多 CheckBox 并根据 table 中的信息只显示其中的一些,这毫无意义。我听说了 listview
但是怎么办 listview of checkbox 我在网上找了一个listview的例子,当我试图插入大信息时,只有一半的信息进来了,所以我被告知做 adapter。
您有如何执行此操作的示例吗?
它的数据库处理程序:
package budgetreport.com.budgetreport;
public class DatabaseHandler extends SQLiteOpenHelper {
// All Static variables
// Database Version
private static final int DATABASE_VERSION = 4;
// Database Name
private static final String DATABASE_NAME = "Records_Item Purcashes";
// Contacts table name
private static final String TABLE_RECORDS = "Records";
// Contacts Table Columns names
private static final String KEY_ID = "ID";
private static final String KEY_PRICE = "Price";
private static final String KEY_ITEM = "Item";
private static final String KEY_DETAILS = "Details";
private static final String KEY_DATE = "Date";
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Creating Tables
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_RECORDS + "("
+ KEY_ID + " INTEGER PRIMARY KEY,"
+ KEY_PRICE + " INTEGER," + KEY_ITEM + " TEXT,"
+ KEY_DETAILS + " TEXT, " + KEY_DATE + " TEXT" + ")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
// Upgrading database
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECORDS);
// Create tables again
onCreate(db);
}
// Adding new contact
public void addRecord(Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId()); // Contact Name
values.put(KEY_PRICE, record.getPrice()); // Contact Name
values.put(KEY_ITEM, record.getItem()); // Contact Name
values.put(KEY_DETAILS, record.getDetails()); // Contact Name
values.put(KEY_DATE, record.getDetails()); // Contact Phone Number
// Inserting Row
db.insert(TABLE_RECORDS, null, values);
db.close(); // Closing database connection
}
// Getting single contact
public Record getRecord(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_RECORDS, new String[] { KEY_ID, KEY_PRICE,
KEY_ITEM, KEY_DETAILS, KEY_DATE }, KEY_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
Record record = new Record(Integer.parseInt(cursor.getString(0)),
Integer.parseInt(cursor.getString(1)), cursor.getString(2), cursor.getString(3), cursor.getString(4));
// return contact
return record;
}
// Getting All Contacts
public List<Record> getAllContacts() {
List<Record> contactList = new ArrayList<Record>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Record record = new Record();
record.setId(Integer.parseInt(cursor.getString(0)));
record.setPrice(Integer.parseInt(cursor.getString(1)));
record.setItem(cursor.getString(2));
record.setDetails(cursor.getString(3));
record.setDate(cursor.getString(4));
// Adding contact to list
contactList.add(record);
} while (cursor.moveToNext());
}
// return contact list
return contactList;
}
// Getting contacts Count
public int getRecordsCount() {
String countQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
// cursor.close();
// return count
return cursor.getCount();
}
// Updating single contact
public int updateContact(Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId());
values.put(KEY_PRICE, record.getPrice());
values.put(KEY_DETAILS, record.getDetails());
values.put(KEY_DATE, record.getDate());
// updating row
return db.update(TABLE_RECORDS, values, KEY_ID + " = ?",
new String[] { String.valueOf(record.getPrice()) });
}
// Deleting single contact
public void deleteContact(Record record) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_RECORDS, KEY_ID + " = ?",new String[]
{String.valueOf(record.getPrice()) });
db.close();
}
}
这是一个基于您的代码的示例。
1) Activity 的布局(即 id 为 lv001 的 ListView)作为文件 activity_main.xml:-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mjt.budgetreport.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_margin="10dp"
/>
<ListView
android:id="@+id/lv001"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
2) 每行的布局(ListView 术语中的 Item)作为文件 listviewitem_record.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/record_price"
android:layout_width="0dp"
android:layout_weight="8"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<TextView
android:id="@+id/record_item"
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<TextView
android:id="@+id/record_details"
android:layout_width="0dp"
android:layout_weight="20"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<TextView
android:id="@+id/record_date"
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<CheckBox
android:id="@+id/record_checkbox"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
</LinearLayout>
- 注意!包含 CheckBox 以及所有列的 TextView。
3) 为了简化问题,我将其用作 DatabaseHandler.java :-
public class DatabaseHandler extends SQLiteOpenHelper {
// All Static variables
// Database Version
private static final int DATABASE_VERSION = 4;
// Database Name
public static final String DATABASE_NAME = "Records_Item Purcashes";
// Contacts table name
public static final String TABLE_RECORDS = "Records";
// Contacts Table Columns names
public static final String KEY_ID = "_id";
public static final String KEY_PRICE = "Price";
public static final String KEY_ITEM = "Item";
public static final String KEY_DETAILS = "Details";
public static final String KEY_DATE = "Date";
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Creating Tables
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " +
TABLE_RECORDS +
"(" +
KEY_ID + " INTEGER PRIMARY KEY," +
KEY_PRICE + " INTEGER," +
KEY_ITEM + " TEXT," +
KEY_DETAILS + " TEXT, " +
KEY_DATE + " TEXT" +
")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
// Upgrading database
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECORDS);
// Create tables again
onCreate(db);
}
public void insertRecord(int price, String item, String details, String date) {
ContentValues cv = new ContentValues();
cv.put(KEY_PRICE,price);
cv.put(KEY_ITEM,item);
cv.put(KEY_DETAILS,details);
cv.put(KEY_DATE,date);
SQLiteDatabase db = this.getWritableDatabase();
db.insert(TABLE_RECORDS,null,cv);
}
public Cursor getAllRecords() {
SQLiteDatabase db = this.getWritableDatabase();
return db.query(TABLE_RECORDS,null,null,null,null,null,null);
}
/*
// Adding new contact
public void addRecord(AlphabeticIndex.Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId()); // Contact Name
values.put(KEY_PRICE, record.getPrice()); // Contact Name
values.put(KEY_ITEM, record.getItem()); // Contact Name
values.put(KEY_DETAILS, record.getDetails()); // Contact Name
values.put(KEY_DATE, record.getDetails()); // Contact Phone Number
// Inserting Row
db.insert(TABLE_RECORDS, null, values);
db.close(); // Closing database connection
}
*/
/*
// Getting single contact
public AlphabeticIndex.Record getRecord(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_RECORDS, new String[] { KEY_ID, KEY_PRICE,
KEY_ITEM, KEY_DETAILS, KEY_DATE }, KEY_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
AlphabeticIndex.Record record = new AlphabeticIndex.Record(Integer.parseInt(cursor.getString(0)),
Integer.parseInt(cursor.getString(1)), cursor.getString(2), cursor.getString(3), cursor.getString(4));
// return contact
return record;
}
*/
/*
// Getting All Contacts
public List<AlphabeticIndex.Record> getAllContacts() {
List<AlphabeticIndex.Record> contactList = new ArrayList<AlphabeticIndex.Record>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
AlphabeticIndex.Record record = new AlphabeticIndex.Record();
record.setId(Integer.parseInt(cursor.getString(0)));
record.setPrice(Integer.parseInt(cursor.getString(1)));
record.setItem(cursor.getString(2));
record.setDetails(cursor.getString(3));
record.setDate(cursor.getString(4));
// Adding contact to list
contactList.add(record);
} while (cursor.moveToNext());
}
// return contact list
return contactList;
}
*/
/*
// Getting contacts Count
public int getRecordsCount() {
String countQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
// cursor.close();
// return count
return cursor.getCount();
}
*/
/*
// Updating single contact
public int updateContact(AlphabeticIndex.Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId());
values.put(KEY_PRICE, record.getPrice());
values.put(KEY_DETAILS, record.getDetails());
values.put(KEY_DATE, record.getDate());
// updating row
return db.update(TABLE_RECORDS, values, KEY_ID + " = ?",
new String[] { String.valueOf(record.getPrice()) });
}
*/
/*
// Deleting single contact
public void deleteContact(AlphabeticIndex.Record record) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_RECORDS, KEY_ID + " = ?",new String[]
{String.valueOf(record.getPrice()) });
db.close();
}
*/
}
关于 DatabaseHandler.java
更改的说明
rowid 别名已从 ID 更改为 _id,这是因为 CursorAdapter 需要一个名为 _id 并且该列应该是 rowid 的别名(此处不涉及技术细节)。
为了方便起见,我没有使用 Record class,而是注释掉了使用此 class 的代码。
我已将 TABLE 和 COLUMN 名称定义更改为 public,因此可以在其他地方访问它们。
我添加了两个新方法 insertRecord
和 getAllRecords
:-
insertRecord
只是为 testing/example 添加一些数据
getAllRecords
将所有行检索为 Cursor
,而不是数组。
- 注意!数据库没有关闭,这会导致异常,因为 Cursor 需要访问数据库(无论如何打开和关闭数据库都是有害的)。
4) Activity 本身(仅在为第一个 运行 添加一些数据后显示 ListView)作为文件 MainActivity.java: -
public class MainActivity extends AppCompatActivity {
DatabaseHandler mDBHandler;
ListView mListView;
SimpleCursorAdapter mSCA;
Cursor mCsr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) this.findViewById(R.id.lv001); // Get the ListView from it's id
mDBHandler = new DatabaseHandler(this); // Get an instance of the Database Handler
// Add some data but only if there is no data
if (DatabaseUtils.queryNumEntries(mDBHandler.getWritableDatabase(),DatabaseHandler.TABLE_RECORDS) < 1) {
mDBHandler.insertRecord(100,"Rock","A large stone.","31/12/2017");
mDBHandler.insertRecord(50,"Boulder","A Rock.","31/12/2018");
mDBHandler.insertRecord(322,"Soil","Loose earth.","31/7/2015");
mDBHandler.insertRecord(237,"Stone","A small rock.","31/8/2014");
mDBHandler.insertRecord(32,"Pebble","A small smooth stone.","11/12/2017");
}
// get all rows into a Cursor
mCsr = mDBHandler.getAllRecords();
// Prepare a list of the columns to get the data from, for the ListViewt
String[] columns_to_get_data_from = new String[]{
DatabaseHandler.KEY_PRICE,
DatabaseHandler.KEY_ITEM,
DatabaseHandler.KEY_DETAILS,
DatabaseHandler.KEY_DATE
};
// Prepare a list of the Views into which to place the data
int[] itemviews_to_place_data_in = new int[]{
R.id.record_price,
R.id.record_item,
R.id.record_details,
R.id.record_date
};
// get and instance of SimpleCursorAdapter
mSCA = new SimpleCursorAdapter(this,
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
0);
// get and instance of SimpleCursorAdapter the listviewitem_record layout
mListView.setAdapter(mSCA);
}
}
结果:-
备注
这不涉及处理复选框,这可能需要一个 CustomAdapter。有很多教程,例如how do i create a custom cursor adapter for a listview for use with images and text?.
编辑修改为包括复选框处理
1) Activity 的布局 activity_main.xml - 添加了一个用于获取选中项目的按钮 :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mjt.budgetreport.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_margin="10dp"
/>
<Button
android:id="@+id/doitbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DO ALL CHECKED ROWS"
/>
<ListView
android:id="@+id/lv001"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
2) 自定义光标适配器 MyCustomCursorAdapter.java
- 类似于 SimpleCursorAdapter 的签名,但带有
CheckBox
. 的 id 的额外参数
- 包括方法
getCheckedRecordIdList
,它将 return 已检查的 ID 列表。
- 在检查或未选中显示该项目的复选框时,请发出敬酒,如ListView的项目#(不是table中的项目),单击和 item [= = = 113=] 单击(如 table 中的项目值)。
:-
public class MyCustomCursorAdapter extends CursorAdapter {
private Context mContext;
private Cursor mCsr;
private String[] mColumns;
private int[] mViews;
private int mLayout;
private boolean[] mCheckBoxStates;
private int mCheckBoxView;
// Constructor for the Custom Cursor Adapter
MyCustomCursorAdapter(Context context, int layout, Cursor csr, String[] from_columns, int[] to_views, int checkbox_view) {
super(context,csr, false);
mContext = context;
mLayout = layout;
mCsr = csr;
mColumns = from_columns;
mViews = to_views;
mCheckBoxView = checkbox_view;
}
@Override
// Inflate the layout we are going to use (as passed via 2nd parameter)
public View newView(Context context, Cursor csr, ViewGroup parent) {
// Initialise an int array for the checkboxes (all will be 0)
mCheckBoxStates = new boolean[csr.getCount()];
return LayoutInflater.from(context).inflate(mLayout,parent,false);
}
@Override
// Tie the from_columns to the display views
public void bindView(View view, Context context, Cursor csr) {
// Place the data from the cursor into the respective View (TextView)
for (int i = 0; i < mColumns.length; i++) {
((TextView) view.findViewById(mViews[i])).setText(csr.getString(csr.getColumnIndex(mColumns[i])));
}
// Set the checkbox (note should be false, unless otherwise changed)
CheckBox currentCheckBox = (CheckBox) view.findViewById(mCheckBoxView);
currentCheckBox.setChecked(mCheckBoxStates[mCsr.getPosition()]);
currentCheckBox.setTag(new Long(mCsr.getLong(mCsr.getColumnIndex(DatabaseHandler.KEY_ID))));
//
currentCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
final int position = mCsr.getPosition();
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Store the checkbox status
mCheckBoxStates[position] = ((CheckBox) buttonView).isChecked();
int restore_cursor_position = mCsr.getPosition();
//Move the Cursor to the respective row
//NOTE! 1st position in Lisview is 1 but equates to cursor row 0 etc hence -1
mCsr.moveToPosition(position);
Toast.makeText(mContext,
"You Changed the CheckBox for row " +
Integer.toString(position + 1) +
" Item is " +
mCsr.getString(mCsr.getColumnIndex(DatabaseHandler.KEY_ITEM))
,
Toast.LENGTH_SHORT
).show();
//restore the Cursor's position
mCsr.moveToPosition(restore_cursor_position);
}
});
}
// get the list of items (the ID's as long) that have been checked.
public long[] getCheckedRecordIdList() {
// using ArrayList as we can add as we don't yet know how many
ArrayList<Long> rva = new ArrayList<>();
// Just in case save the current position of the Cursor
int restore_cursor_position = mCsr.getPosition();
// Loop through the checkbox states
for (int i=0; i < mCheckBoxStates.length; i++) {
// If the checkbox reflected as being checked then handle, else ignore it
if (mCheckBoxStates[i]) {
// Move to the respective cursor row
mCsr.moveToPosition(i);
// get the respective ID and store in the arraylist
rva.add(mCsr.getLong(mCsr.getColumnIndex(DatabaseHandler.KEY_ID)));
}
}
// Done with the Cursor so re-position it
mCsr.moveToPosition(restore_cursor_position);
// Create the long array to be returned
long[] rv = new long[rva.size()];
// Populate the long array with the id's from the arraylist
for (int i=0; i < rva.size(); i++) {
rv[i] = rva.get(i);
}
// return the long[]
return rv;
}
}
3) 修改后的 MainActivity 以使用自定义适配器并获取已检查记录的列表(显示通过 Toast 选择的数量)- MainActivity.java
- Changed/Added Lines/Methods 标记为 <<<<<.
:-
public class MainActivity extends AppCompatActivity {
DatabaseHandler mDBHandler;
ListView mListView;
SimpleCursorAdapter mSCA;
MyCustomCursorAdapter mMCA; // <<<<<
Cursor mCsr;
Button mDoItButton;
Context mContext; //<<<<<
long[] mCheckedIdList; //<<<<<
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
mListView = (ListView) this.findViewById(R.id.lv001); // Get the ListView from it's id
mDoItButton = (Button) this.findViewById(R.id.doitbutton); //<<<<<
mDBHandler = new DatabaseHandler(this); // Get an instance of the Database Handler
// Add some data but only if there is no data
if (DatabaseUtils.queryNumEntries(mDBHandler.getWritableDatabase(),DatabaseHandler.TABLE_RECORDS) < 1) {
mDBHandler.insertRecord(100,"Rock","A large stone.","31/12/2017");
mDBHandler.insertRecord(50,"Boulder","A Rock.","31/12/2018");
mDBHandler.insertRecord(322,"Soil","Loose earth.","31/7/2015");
mDBHandler.insertRecord(237,"Stone","A small rock.","31/8/2014");
mDBHandler.insertRecord(32,"Pebble","A small smooth stone.","11/12/2017");
}
mDBHandler.increasePrice(1,213);
// get all rows into a Cursor
mCsr = mDBHandler.getAllRecords();
// Prepare a list of the columns to get the data from, for the ListViewt
String[] columns_to_get_data_from = new String[]{
DatabaseHandler.KEY_ID,
DatabaseHandler.KEY_PRICE,
DatabaseHandler.KEY_ITEM,
DatabaseHandler.KEY_DETAILS,
DatabaseHandler.KEY_DATE
};
// Prepare a list of the Views into which to place the data
int[] itemviews_to_place_data_in = new int[]{
R.id.record_id,
R.id.record_price,
R.id.record_item,
R.id.record_details,
R.id.record_date
};
// get and instance of SimpleCursorAdapter the listviewitem_record layout
mSCA = new SimpleCursorAdapter(this,
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
0);
// Tie the adapter to the Listview
mListView.setAdapter(mSCA);
// <<<<<< Alternate Custom Cursor Adapter
mMCA = new MyCustomCursorAdapter(this,
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
R.id.record_checkbox //<<<<<< id of the checkbox
);
// Hijack the Listview
mListView.setAdapter(mMCA); //<<<<<<
// <<<<< DO IT BUTTON HANDLER i.e. get list of ID's for checked items
mDoItButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// get the ID's for the checked Items
mCheckedIdList = mMCA.getCheckedRecordIdList();
Toast.makeText(mContext,"You have " + mCheckedIdList.length + " Items checked.",Toast.LENGTH_SHORT).show();
}
});
}
}
注意!您通常不会有两个适配器,但我留下了 SimpleCursorAdapter 用于比较。
注意!有点耐心,如果你点击太多太快,你可能会感到困惑。
注意!请参阅删除选中项目的其他答案。
根据删除选中的项目我想删除我标记的行。
这是比较容易进步的。
涉及
- a) 给数据库助手添加一个方法来根据id删除。
- b) (i) 修改 onClick
侦听器以调用 delete 方法(简单循环),然后 (ii) 更新列表视图(在循环之后)。
但是,原来的自定义适配器存在一些缺陷,即通过mCsr保留了原始光标,并且没有考虑更改(交换)Cursor时更改的复选框数。
因此,适配器已删除对 mCsr 的引用,并替换为传递的 Cursor 或通过调用 getCursor
方法。此外,swapCursor()
方法已被覆盖以调整元素的数量并重新初始化 mCheckBoxes 的 elemnets(设置为 false)。
a)新的deleteRecord
方法:-
public boolean deleteRecord(long id) {
SQLiteDatabase db = this.getWritableDatabase();
return (db.delete(TABLE_RECORDS,KEY_ID + "=?",new String[]{Long.toString(id)})> 0);
}
b)(i) onCLickListener
修改(注意包括将所有删除分组到一个事务中):-
// <<<<< DO IT BUTTON HANDLER i.e. get list of ID's for checked items
mDoItButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// get the ID's for the checked Items
mCheckedIdList = mMCA.getCheckedRecordIdList();
Toast.makeText(mContext,"You have " + mCheckedIdList.length + " Items checked.",Toast.LENGTH_SHORT).show();
//<<<< to delete
SQLiteDatabase db = mDBHandler.getWritableDatabase();
db.beginTransaction();
for (long id: mCheckedIdList) {
mDBHandler.deleteRecord(id);
}
db.setTransactionSuccessful();
db.endTransaction();
refreshListView();
}
});
b(ii) 更新 Listview(Activity 中的新方法):-
private void refreshListView() {
mCsr = mDBHandler.getAllRecords();
mMCA.swapCursor(mCsr);
}
注释
- 这是作为方法添加到 activity。
- mMCA.notifyDatasetChanged();是另一种选择(我个人更喜欢 `swapCursor1,因为它更具描述性)。
修改后的 Custom Cursor Adapter 应该是:-
public class MyCustomCursorAdapter extends CursorAdapter {
private Context mContext;
private String[] mColumns;
private int[] mViews;
private int mLayout;
private boolean[] mCheckBoxStates;
private int mCheckBoxView;
// Constructor for the Custom Cursor Adapter
MyCustomCursorAdapter(Context context, int layout, Cursor csr, String[] from_columns, int[] to_views, int checkbox_view) {
super(context,csr, false);
mContext = context;
mLayout = layout;
mColumns = from_columns;
mViews = to_views;
mCheckBoxView = checkbox_view;
}
@Override
// Inflate the layout we are going to use (as passed via 2nd parameter)
public View newView(Context context, Cursor csr, ViewGroup parent) {
// Initialise an int array for the checkboxes (all will be 0)
mCheckBoxStates = new boolean[csr.getCount()];
return LayoutInflater.from(context).inflate(mLayout,parent,false);
}
@Override
// Tie the from_columns to the display views
public void bindView(View view, Context context, Cursor csr) {
final Cursor fcsr = csr;
// Place the data from the cursor into the respective View (TextView)
for (int i = 0; i < mColumns.length; i++) {
((TextView) view.findViewById(mViews[i])).setText(csr.getString(csr.getColumnIndex(mColumns[i])));
}
// Set the checkbox (note should be false, unless otherwise changed)
CheckBox currentCheckBox = (CheckBox) view.findViewById(mCheckBoxView);
currentCheckBox.setChecked(mCheckBoxStates[csr.getPosition()]);
currentCheckBox.setTag(new Long(csr.getLong(csr.getColumnIndex(DatabaseHandler.KEY_ID))));
//
currentCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
final int position = fcsr.getPosition();
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Store the checkbox status
mCheckBoxStates[position] = ((CheckBox) buttonView).isChecked();
int restore_cursor_position = fcsr.getPosition();
//Move the Cursor to the respective row
//NOTE! 1st position in Lisview is 1 but equates to cursor row 0 etc hence -1
fcsr.moveToPosition(position);
Toast.makeText(mContext,
"You Changed the CheckBox for row " +
Integer.toString(position + 1) +
" Item is " +
fcsr.getString(fcsr.getColumnIndex(DatabaseHandler.KEY_ITEM))
,
Toast.LENGTH_SHORT
).show();
//restore the Cursor's position
fcsr.moveToPosition(restore_cursor_position);
}
});
}
// get the list of items (the ID's as long) that have been checked.
public long[] getCheckedRecordIdList() {
Cursor csr = this.getCursor();
// using ArrayList as we can add as we don't yet know how many
ArrayList<Long> rva = new ArrayList<>();
// Just in case save the current position of the Cursor
int restore_cursor_position = csr.getPosition();
// Loop through the checkbox states
for (int i=0; i < mCheckBoxStates.length; i++) {
// If the checkbox reflected as being checked then handle, else ignore it
if (mCheckBoxStates[i]) {
// Move to the respective cursor row
csr.moveToPosition(i);
// get the respective ID and store in the arraylist
rva.add(csr.getLong(csr.getColumnIndex(DatabaseHandler.KEY_ID)));
}
}
// Done with the Cursor so re-position it
csr.moveToPosition(restore_cursor_position);
// Create the long array to be returned
long[] rv = new long[rva.size()];
// Populate the long array with the id's from the arraylist
for (int i=0; i < rva.size(); i++) {
rv[i] = rva.get(i);
}
// return the long[]
return rv;
}
@Override
public Cursor swapCursor(Cursor csr) {
mCheckBoxStates = new boolean[csr.getCount()];
for (int i=0; i < mCheckBoxStates.length; i++) {
mCheckBoxStates[i] = false;
}
return super.swapCursor(csr);
}
}
我在数据库中有一个 table,我想创建一个 table。 现在,我会做很多 CheckBox 并根据 table 中的信息只显示其中的一些,这毫无意义。我听说了 listview 但是怎么办 listview of checkbox 我在网上找了一个listview的例子,当我试图插入大信息时,只有一半的信息进来了,所以我被告知做 adapter。 您有如何执行此操作的示例吗?
它的数据库处理程序:
package budgetreport.com.budgetreport;
public class DatabaseHandler extends SQLiteOpenHelper {
// All Static variables
// Database Version
private static final int DATABASE_VERSION = 4;
// Database Name
private static final String DATABASE_NAME = "Records_Item Purcashes";
// Contacts table name
private static final String TABLE_RECORDS = "Records";
// Contacts Table Columns names
private static final String KEY_ID = "ID";
private static final String KEY_PRICE = "Price";
private static final String KEY_ITEM = "Item";
private static final String KEY_DETAILS = "Details";
private static final String KEY_DATE = "Date";
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Creating Tables
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_RECORDS + "("
+ KEY_ID + " INTEGER PRIMARY KEY,"
+ KEY_PRICE + " INTEGER," + KEY_ITEM + " TEXT,"
+ KEY_DETAILS + " TEXT, " + KEY_DATE + " TEXT" + ")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
// Upgrading database
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECORDS);
// Create tables again
onCreate(db);
}
// Adding new contact
public void addRecord(Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId()); // Contact Name
values.put(KEY_PRICE, record.getPrice()); // Contact Name
values.put(KEY_ITEM, record.getItem()); // Contact Name
values.put(KEY_DETAILS, record.getDetails()); // Contact Name
values.put(KEY_DATE, record.getDetails()); // Contact Phone Number
// Inserting Row
db.insert(TABLE_RECORDS, null, values);
db.close(); // Closing database connection
}
// Getting single contact
public Record getRecord(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_RECORDS, new String[] { KEY_ID, KEY_PRICE,
KEY_ITEM, KEY_DETAILS, KEY_DATE }, KEY_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
Record record = new Record(Integer.parseInt(cursor.getString(0)),
Integer.parseInt(cursor.getString(1)), cursor.getString(2), cursor.getString(3), cursor.getString(4));
// return contact
return record;
}
// Getting All Contacts
public List<Record> getAllContacts() {
List<Record> contactList = new ArrayList<Record>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Record record = new Record();
record.setId(Integer.parseInt(cursor.getString(0)));
record.setPrice(Integer.parseInt(cursor.getString(1)));
record.setItem(cursor.getString(2));
record.setDetails(cursor.getString(3));
record.setDate(cursor.getString(4));
// Adding contact to list
contactList.add(record);
} while (cursor.moveToNext());
}
// return contact list
return contactList;
}
// Getting contacts Count
public int getRecordsCount() {
String countQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
// cursor.close();
// return count
return cursor.getCount();
}
// Updating single contact
public int updateContact(Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId());
values.put(KEY_PRICE, record.getPrice());
values.put(KEY_DETAILS, record.getDetails());
values.put(KEY_DATE, record.getDate());
// updating row
return db.update(TABLE_RECORDS, values, KEY_ID + " = ?",
new String[] { String.valueOf(record.getPrice()) });
}
// Deleting single contact
public void deleteContact(Record record) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_RECORDS, KEY_ID + " = ?",new String[]
{String.valueOf(record.getPrice()) });
db.close();
}
}
这是一个基于您的代码的示例。
1) Activity 的布局(即 id 为 lv001 的 ListView)作为文件 activity_main.xml:-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mjt.budgetreport.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_margin="10dp"
/>
<ListView
android:id="@+id/lv001"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
2) 每行的布局(ListView 术语中的 Item)作为文件 listviewitem_record.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/record_price"
android:layout_width="0dp"
android:layout_weight="8"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<TextView
android:id="@+id/record_item"
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<TextView
android:id="@+id/record_details"
android:layout_width="0dp"
android:layout_weight="20"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<TextView
android:id="@+id/record_date"
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<CheckBox
android:id="@+id/record_checkbox"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
</LinearLayout>
- 注意!包含 CheckBox 以及所有列的 TextView。
3) 为了简化问题,我将其用作 DatabaseHandler.java :-
public class DatabaseHandler extends SQLiteOpenHelper {
// All Static variables
// Database Version
private static final int DATABASE_VERSION = 4;
// Database Name
public static final String DATABASE_NAME = "Records_Item Purcashes";
// Contacts table name
public static final String TABLE_RECORDS = "Records";
// Contacts Table Columns names
public static final String KEY_ID = "_id";
public static final String KEY_PRICE = "Price";
public static final String KEY_ITEM = "Item";
public static final String KEY_DETAILS = "Details";
public static final String KEY_DATE = "Date";
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Creating Tables
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " +
TABLE_RECORDS +
"(" +
KEY_ID + " INTEGER PRIMARY KEY," +
KEY_PRICE + " INTEGER," +
KEY_ITEM + " TEXT," +
KEY_DETAILS + " TEXT, " +
KEY_DATE + " TEXT" +
")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
// Upgrading database
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECORDS);
// Create tables again
onCreate(db);
}
public void insertRecord(int price, String item, String details, String date) {
ContentValues cv = new ContentValues();
cv.put(KEY_PRICE,price);
cv.put(KEY_ITEM,item);
cv.put(KEY_DETAILS,details);
cv.put(KEY_DATE,date);
SQLiteDatabase db = this.getWritableDatabase();
db.insert(TABLE_RECORDS,null,cv);
}
public Cursor getAllRecords() {
SQLiteDatabase db = this.getWritableDatabase();
return db.query(TABLE_RECORDS,null,null,null,null,null,null);
}
/*
// Adding new contact
public void addRecord(AlphabeticIndex.Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId()); // Contact Name
values.put(KEY_PRICE, record.getPrice()); // Contact Name
values.put(KEY_ITEM, record.getItem()); // Contact Name
values.put(KEY_DETAILS, record.getDetails()); // Contact Name
values.put(KEY_DATE, record.getDetails()); // Contact Phone Number
// Inserting Row
db.insert(TABLE_RECORDS, null, values);
db.close(); // Closing database connection
}
*/
/*
// Getting single contact
public AlphabeticIndex.Record getRecord(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_RECORDS, new String[] { KEY_ID, KEY_PRICE,
KEY_ITEM, KEY_DETAILS, KEY_DATE }, KEY_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
AlphabeticIndex.Record record = new AlphabeticIndex.Record(Integer.parseInt(cursor.getString(0)),
Integer.parseInt(cursor.getString(1)), cursor.getString(2), cursor.getString(3), cursor.getString(4));
// return contact
return record;
}
*/
/*
// Getting All Contacts
public List<AlphabeticIndex.Record> getAllContacts() {
List<AlphabeticIndex.Record> contactList = new ArrayList<AlphabeticIndex.Record>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
AlphabeticIndex.Record record = new AlphabeticIndex.Record();
record.setId(Integer.parseInt(cursor.getString(0)));
record.setPrice(Integer.parseInt(cursor.getString(1)));
record.setItem(cursor.getString(2));
record.setDetails(cursor.getString(3));
record.setDate(cursor.getString(4));
// Adding contact to list
contactList.add(record);
} while (cursor.moveToNext());
}
// return contact list
return contactList;
}
*/
/*
// Getting contacts Count
public int getRecordsCount() {
String countQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
// cursor.close();
// return count
return cursor.getCount();
}
*/
/*
// Updating single contact
public int updateContact(AlphabeticIndex.Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId());
values.put(KEY_PRICE, record.getPrice());
values.put(KEY_DETAILS, record.getDetails());
values.put(KEY_DATE, record.getDate());
// updating row
return db.update(TABLE_RECORDS, values, KEY_ID + " = ?",
new String[] { String.valueOf(record.getPrice()) });
}
*/
/*
// Deleting single contact
public void deleteContact(AlphabeticIndex.Record record) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_RECORDS, KEY_ID + " = ?",new String[]
{String.valueOf(record.getPrice()) });
db.close();
}
*/
}
关于 DatabaseHandler.java
更改的说明rowid 别名已从 ID 更改为 _id,这是因为 CursorAdapter 需要一个名为 _id 并且该列应该是 rowid 的别名(此处不涉及技术细节)。
为了方便起见,我没有使用 Record class,而是注释掉了使用此 class 的代码。
我已将 TABLE 和 COLUMN 名称定义更改为 public,因此可以在其他地方访问它们。
我添加了两个新方法
insertRecord
和getAllRecords
:-insertRecord
只是为 testing/example 添加一些数据
getAllRecords
将所有行检索为Cursor
,而不是数组。- 注意!数据库没有关闭,这会导致异常,因为 Cursor 需要访问数据库(无论如何打开和关闭数据库都是有害的)。
4) Activity 本身(仅在为第一个 运行 添加一些数据后显示 ListView)作为文件 MainActivity.java: -
public class MainActivity extends AppCompatActivity {
DatabaseHandler mDBHandler;
ListView mListView;
SimpleCursorAdapter mSCA;
Cursor mCsr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) this.findViewById(R.id.lv001); // Get the ListView from it's id
mDBHandler = new DatabaseHandler(this); // Get an instance of the Database Handler
// Add some data but only if there is no data
if (DatabaseUtils.queryNumEntries(mDBHandler.getWritableDatabase(),DatabaseHandler.TABLE_RECORDS) < 1) {
mDBHandler.insertRecord(100,"Rock","A large stone.","31/12/2017");
mDBHandler.insertRecord(50,"Boulder","A Rock.","31/12/2018");
mDBHandler.insertRecord(322,"Soil","Loose earth.","31/7/2015");
mDBHandler.insertRecord(237,"Stone","A small rock.","31/8/2014");
mDBHandler.insertRecord(32,"Pebble","A small smooth stone.","11/12/2017");
}
// get all rows into a Cursor
mCsr = mDBHandler.getAllRecords();
// Prepare a list of the columns to get the data from, for the ListViewt
String[] columns_to_get_data_from = new String[]{
DatabaseHandler.KEY_PRICE,
DatabaseHandler.KEY_ITEM,
DatabaseHandler.KEY_DETAILS,
DatabaseHandler.KEY_DATE
};
// Prepare a list of the Views into which to place the data
int[] itemviews_to_place_data_in = new int[]{
R.id.record_price,
R.id.record_item,
R.id.record_details,
R.id.record_date
};
// get and instance of SimpleCursorAdapter
mSCA = new SimpleCursorAdapter(this,
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
0);
// get and instance of SimpleCursorAdapter the listviewitem_record layout
mListView.setAdapter(mSCA);
}
}
结果:-
备注
这不涉及处理复选框,这可能需要一个 CustomAdapter。有很多教程,例如how do i create a custom cursor adapter for a listview for use with images and text?.
编辑修改为包括复选框处理
1) Activity 的布局 activity_main.xml - 添加了一个用于获取选中项目的按钮 :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mjt.budgetreport.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_margin="10dp"
/>
<Button
android:id="@+id/doitbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DO ALL CHECKED ROWS"
/>
<ListView
android:id="@+id/lv001"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
2) 自定义光标适配器 MyCustomCursorAdapter.java
- 类似于 SimpleCursorAdapter 的签名,但带有
CheckBox
. 的 id 的额外参数
- 包括方法
getCheckedRecordIdList
,它将 return 已检查的 ID 列表。 - 在检查或未选中显示该项目的复选框时,请发出敬酒,如ListView的项目#(不是table中的项目),单击和 item [= = = 113=] 单击(如 table 中的项目值)。
:-
public class MyCustomCursorAdapter extends CursorAdapter {
private Context mContext;
private Cursor mCsr;
private String[] mColumns;
private int[] mViews;
private int mLayout;
private boolean[] mCheckBoxStates;
private int mCheckBoxView;
// Constructor for the Custom Cursor Adapter
MyCustomCursorAdapter(Context context, int layout, Cursor csr, String[] from_columns, int[] to_views, int checkbox_view) {
super(context,csr, false);
mContext = context;
mLayout = layout;
mCsr = csr;
mColumns = from_columns;
mViews = to_views;
mCheckBoxView = checkbox_view;
}
@Override
// Inflate the layout we are going to use (as passed via 2nd parameter)
public View newView(Context context, Cursor csr, ViewGroup parent) {
// Initialise an int array for the checkboxes (all will be 0)
mCheckBoxStates = new boolean[csr.getCount()];
return LayoutInflater.from(context).inflate(mLayout,parent,false);
}
@Override
// Tie the from_columns to the display views
public void bindView(View view, Context context, Cursor csr) {
// Place the data from the cursor into the respective View (TextView)
for (int i = 0; i < mColumns.length; i++) {
((TextView) view.findViewById(mViews[i])).setText(csr.getString(csr.getColumnIndex(mColumns[i])));
}
// Set the checkbox (note should be false, unless otherwise changed)
CheckBox currentCheckBox = (CheckBox) view.findViewById(mCheckBoxView);
currentCheckBox.setChecked(mCheckBoxStates[mCsr.getPosition()]);
currentCheckBox.setTag(new Long(mCsr.getLong(mCsr.getColumnIndex(DatabaseHandler.KEY_ID))));
//
currentCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
final int position = mCsr.getPosition();
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Store the checkbox status
mCheckBoxStates[position] = ((CheckBox) buttonView).isChecked();
int restore_cursor_position = mCsr.getPosition();
//Move the Cursor to the respective row
//NOTE! 1st position in Lisview is 1 but equates to cursor row 0 etc hence -1
mCsr.moveToPosition(position);
Toast.makeText(mContext,
"You Changed the CheckBox for row " +
Integer.toString(position + 1) +
" Item is " +
mCsr.getString(mCsr.getColumnIndex(DatabaseHandler.KEY_ITEM))
,
Toast.LENGTH_SHORT
).show();
//restore the Cursor's position
mCsr.moveToPosition(restore_cursor_position);
}
});
}
// get the list of items (the ID's as long) that have been checked.
public long[] getCheckedRecordIdList() {
// using ArrayList as we can add as we don't yet know how many
ArrayList<Long> rva = new ArrayList<>();
// Just in case save the current position of the Cursor
int restore_cursor_position = mCsr.getPosition();
// Loop through the checkbox states
for (int i=0; i < mCheckBoxStates.length; i++) {
// If the checkbox reflected as being checked then handle, else ignore it
if (mCheckBoxStates[i]) {
// Move to the respective cursor row
mCsr.moveToPosition(i);
// get the respective ID and store in the arraylist
rva.add(mCsr.getLong(mCsr.getColumnIndex(DatabaseHandler.KEY_ID)));
}
}
// Done with the Cursor so re-position it
mCsr.moveToPosition(restore_cursor_position);
// Create the long array to be returned
long[] rv = new long[rva.size()];
// Populate the long array with the id's from the arraylist
for (int i=0; i < rva.size(); i++) {
rv[i] = rva.get(i);
}
// return the long[]
return rv;
}
}
3) 修改后的 MainActivity 以使用自定义适配器并获取已检查记录的列表(显示通过 Toast 选择的数量)- MainActivity.java
- Changed/Added Lines/Methods 标记为 <<<<<.
:-
public class MainActivity extends AppCompatActivity {
DatabaseHandler mDBHandler;
ListView mListView;
SimpleCursorAdapter mSCA;
MyCustomCursorAdapter mMCA; // <<<<<
Cursor mCsr;
Button mDoItButton;
Context mContext; //<<<<<
long[] mCheckedIdList; //<<<<<
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
mListView = (ListView) this.findViewById(R.id.lv001); // Get the ListView from it's id
mDoItButton = (Button) this.findViewById(R.id.doitbutton); //<<<<<
mDBHandler = new DatabaseHandler(this); // Get an instance of the Database Handler
// Add some data but only if there is no data
if (DatabaseUtils.queryNumEntries(mDBHandler.getWritableDatabase(),DatabaseHandler.TABLE_RECORDS) < 1) {
mDBHandler.insertRecord(100,"Rock","A large stone.","31/12/2017");
mDBHandler.insertRecord(50,"Boulder","A Rock.","31/12/2018");
mDBHandler.insertRecord(322,"Soil","Loose earth.","31/7/2015");
mDBHandler.insertRecord(237,"Stone","A small rock.","31/8/2014");
mDBHandler.insertRecord(32,"Pebble","A small smooth stone.","11/12/2017");
}
mDBHandler.increasePrice(1,213);
// get all rows into a Cursor
mCsr = mDBHandler.getAllRecords();
// Prepare a list of the columns to get the data from, for the ListViewt
String[] columns_to_get_data_from = new String[]{
DatabaseHandler.KEY_ID,
DatabaseHandler.KEY_PRICE,
DatabaseHandler.KEY_ITEM,
DatabaseHandler.KEY_DETAILS,
DatabaseHandler.KEY_DATE
};
// Prepare a list of the Views into which to place the data
int[] itemviews_to_place_data_in = new int[]{
R.id.record_id,
R.id.record_price,
R.id.record_item,
R.id.record_details,
R.id.record_date
};
// get and instance of SimpleCursorAdapter the listviewitem_record layout
mSCA = new SimpleCursorAdapter(this,
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
0);
// Tie the adapter to the Listview
mListView.setAdapter(mSCA);
// <<<<<< Alternate Custom Cursor Adapter
mMCA = new MyCustomCursorAdapter(this,
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
R.id.record_checkbox //<<<<<< id of the checkbox
);
// Hijack the Listview
mListView.setAdapter(mMCA); //<<<<<<
// <<<<< DO IT BUTTON HANDLER i.e. get list of ID's for checked items
mDoItButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// get the ID's for the checked Items
mCheckedIdList = mMCA.getCheckedRecordIdList();
Toast.makeText(mContext,"You have " + mCheckedIdList.length + " Items checked.",Toast.LENGTH_SHORT).show();
}
});
}
}
注意!您通常不会有两个适配器,但我留下了 SimpleCursorAdapter 用于比较。
注意!有点耐心,如果你点击太多太快,你可能会感到困惑。
注意!请参阅删除选中项目的其他答案。
根据删除选中的项目我想删除我标记的行。
这是比较容易进步的。
涉及
- a) 给数据库助手添加一个方法来根据id删除。
- b) (i) 修改 onClick
侦听器以调用 delete 方法(简单循环),然后 (ii) 更新列表视图(在循环之后)。
但是,原来的自定义适配器存在一些缺陷,即通过mCsr保留了原始光标,并且没有考虑更改(交换)Cursor时更改的复选框数。
因此,适配器已删除对 mCsr 的引用,并替换为传递的 Cursor 或通过调用 getCursor
方法。此外,swapCursor()
方法已被覆盖以调整元素的数量并重新初始化 mCheckBoxes 的 elemnets(设置为 false)。
a)新的deleteRecord
方法:-
public boolean deleteRecord(long id) {
SQLiteDatabase db = this.getWritableDatabase();
return (db.delete(TABLE_RECORDS,KEY_ID + "=?",new String[]{Long.toString(id)})> 0);
}
b)(i) onCLickListener
修改(注意包括将所有删除分组到一个事务中):-
// <<<<< DO IT BUTTON HANDLER i.e. get list of ID's for checked items
mDoItButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// get the ID's for the checked Items
mCheckedIdList = mMCA.getCheckedRecordIdList();
Toast.makeText(mContext,"You have " + mCheckedIdList.length + " Items checked.",Toast.LENGTH_SHORT).show();
//<<<< to delete
SQLiteDatabase db = mDBHandler.getWritableDatabase();
db.beginTransaction();
for (long id: mCheckedIdList) {
mDBHandler.deleteRecord(id);
}
db.setTransactionSuccessful();
db.endTransaction();
refreshListView();
}
});
b(ii) 更新 Listview(Activity 中的新方法):-
private void refreshListView() {
mCsr = mDBHandler.getAllRecords();
mMCA.swapCursor(mCsr);
}
注释
- 这是作为方法添加到 activity。
- mMCA.notifyDatasetChanged();是另一种选择(我个人更喜欢 `swapCursor1,因为它更具描述性)。
修改后的 Custom Cursor Adapter 应该是:-
public class MyCustomCursorAdapter extends CursorAdapter {
private Context mContext;
private String[] mColumns;
private int[] mViews;
private int mLayout;
private boolean[] mCheckBoxStates;
private int mCheckBoxView;
// Constructor for the Custom Cursor Adapter
MyCustomCursorAdapter(Context context, int layout, Cursor csr, String[] from_columns, int[] to_views, int checkbox_view) {
super(context,csr, false);
mContext = context;
mLayout = layout;
mColumns = from_columns;
mViews = to_views;
mCheckBoxView = checkbox_view;
}
@Override
// Inflate the layout we are going to use (as passed via 2nd parameter)
public View newView(Context context, Cursor csr, ViewGroup parent) {
// Initialise an int array for the checkboxes (all will be 0)
mCheckBoxStates = new boolean[csr.getCount()];
return LayoutInflater.from(context).inflate(mLayout,parent,false);
}
@Override
// Tie the from_columns to the display views
public void bindView(View view, Context context, Cursor csr) {
final Cursor fcsr = csr;
// Place the data from the cursor into the respective View (TextView)
for (int i = 0; i < mColumns.length; i++) {
((TextView) view.findViewById(mViews[i])).setText(csr.getString(csr.getColumnIndex(mColumns[i])));
}
// Set the checkbox (note should be false, unless otherwise changed)
CheckBox currentCheckBox = (CheckBox) view.findViewById(mCheckBoxView);
currentCheckBox.setChecked(mCheckBoxStates[csr.getPosition()]);
currentCheckBox.setTag(new Long(csr.getLong(csr.getColumnIndex(DatabaseHandler.KEY_ID))));
//
currentCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
final int position = fcsr.getPosition();
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Store the checkbox status
mCheckBoxStates[position] = ((CheckBox) buttonView).isChecked();
int restore_cursor_position = fcsr.getPosition();
//Move the Cursor to the respective row
//NOTE! 1st position in Lisview is 1 but equates to cursor row 0 etc hence -1
fcsr.moveToPosition(position);
Toast.makeText(mContext,
"You Changed the CheckBox for row " +
Integer.toString(position + 1) +
" Item is " +
fcsr.getString(fcsr.getColumnIndex(DatabaseHandler.KEY_ITEM))
,
Toast.LENGTH_SHORT
).show();
//restore the Cursor's position
fcsr.moveToPosition(restore_cursor_position);
}
});
}
// get the list of items (the ID's as long) that have been checked.
public long[] getCheckedRecordIdList() {
Cursor csr = this.getCursor();
// using ArrayList as we can add as we don't yet know how many
ArrayList<Long> rva = new ArrayList<>();
// Just in case save the current position of the Cursor
int restore_cursor_position = csr.getPosition();
// Loop through the checkbox states
for (int i=0; i < mCheckBoxStates.length; i++) {
// If the checkbox reflected as being checked then handle, else ignore it
if (mCheckBoxStates[i]) {
// Move to the respective cursor row
csr.moveToPosition(i);
// get the respective ID and store in the arraylist
rva.add(csr.getLong(csr.getColumnIndex(DatabaseHandler.KEY_ID)));
}
}
// Done with the Cursor so re-position it
csr.moveToPosition(restore_cursor_position);
// Create the long array to be returned
long[] rv = new long[rva.size()];
// Populate the long array with the id's from the arraylist
for (int i=0; i < rva.size(); i++) {
rv[i] = rva.get(i);
}
// return the long[]
return rv;
}
@Override
public Cursor swapCursor(Cursor csr) {
mCheckBoxStates = new boolean[csr.getCount()];
for (int i=0; i < mCheckBoxStates.length; i++) {
mCheckBoxStates[i] = false;
}
return super.swapCursor(csr);
}
}