使用OnItemClickListener从ListView和数据库中删除项目 [英] Deleting item from ListView and Database with OnItemClickListener
问题描述
我创建了一个数据库,并设法将添加的项目显示到ListView中.现在,我需要一种从ListView和数据库中删除项目的方法.
I created a database and managed to display the added items into a ListView. Now I need a method to delete an item from the ListView and the Database.
public class ZeigeFaecherListe extends AppCompatActivity {
DatabaseHelper myDb;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.zeige_faecher);
myDb = new DatabaseHelper(this);
ListView listViewFaecher = (ListView) findViewById(R.id.listViewFaecher);
final ArrayList<String> faecherListe = new ArrayList<>();
Cursor res = myDb.zeigeFaecher();
if (res.getCount() == 0){
Toast.makeText(ZeigeFaecherListe.this, "Keine Fächer gefunden", Toast.LENGTH_LONG).show();
} else {
while (res.moveToNext()){
faecherListe.add(res.getString(1));
ListAdapter fachListAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, faecherListe);
listViewFaecher.setAdapter(fachListAdapter);
}
}
listViewFaecher.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
}
});
}
}
推荐答案
简而言之,您需要能够通过ListView可用的数据来区分要删除的行.如果从游标中检索到的值作为第二列(即使用res.getString(1))
,提取的字符串,并且该值是唯一的),则可以检索该值并将其用于删除.
In short, you need to be able to distinguish a row for deletion by the data available to the ListView. If the value retrieved from the cursor, as the 2nd column (i.e. the String extracted by using res.getString(1))
, and the value is going the be unique, you can retrieve this and use it for the deletion.
但是,有一些问题,使用ListAdapter
可能还不够.还有其他适配器,例如ArrayAdapter,提供更多功能,重要的是 notifyDatasetChanged
方法(将刷新关联的ListView).
However, there are a few issues, using a ListAdapter
will probably not be sufficient. There are other adapters, such as an ArrayAdapter that offer more features and importantly a notifyDatasetChanged
method (that will refresh the associated ListView).
为游标的每次迭代创建一个新的适配器是一种浪费.因此,适配器应该在循环外部创建,并且只能创建一次.
It is a waste to create a new adapter for each iteration of the cursor. So the adapter should be created outside of the loop and just the once.
我建议删除项目单击会太容易导致意外点击,而删除项目LongClick会容易导致意外删除.
I'd suggest that deleting on item click will be too prone to accidental clicking, deleting on item LongClick would be far less prone to accidental deletion.
如果将变量移动为类变量,则不必将其声明为final.
If you move variables to be class variables you don't have to declare them as final.
因此,根据以上所述,您可能会:-
So based upon the above, you could have :-
public class ZeigeFaecherListe extends AppCompatActivity {
DatabaseHelper myDb;
Cursor res;
ListView listViewFaecher;
ArrayAdapter<String> fachListAdapter;
ArrayList<String> faecherListe;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.zeige_faecher);
listViewFaecher = (ListView) this.findViewById(R.id.listview);
myDb = new DatabaseHelper(this);
addSomeData(); //<<<<<<<<<< ADDED for testing
faecherListe = new ArrayList<>();
res = myDb.zeigeFaecher();
while (res.moveToNext()) {
faecherListe.add(res.getString(1));
}
//<<<< NOTE outside of the loop as this only needs to be done once
fachListAdapter = new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_1,
faecherListe
);
listViewFaecher.setAdapter(fachListAdapter);
//<<<<< NOTE used LONG CLICK listener (less likely to accidentally delete)
listViewFaecher.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
myDb.deleteRow((String)fachListAdapter.getItem(position));
faecherListe.remove(position);
fachListAdapter.notifyDataSetChanged();
return true; //<<<< Indicate that this longclick has been used
}
});
}
private void addSomeData() {
for (int i=1; i <= 10; i++) {
myDb.addRow("Row " + String.valueOf(i));
}
}
}
与上述 deletRow
方法相同的是:-
Along with the above the deletRow
method is :-
public int deleteRow(String col2) {
SQLiteDatabase db = this.getWritableDatabase();
return db.delete(TB001,COL_TB001_DATA + "=?",new String[]{col2});
}
- 哪里
- TB001 是设置为表名称的常量字符串.
- COL_TB001_DATA 是第二列的列名.
- where
- TB001 is a constant String thatis set to the table's name.
- COL_TB001_DATA is the column name of the 2nd column.
警告仅当第二列包含唯一数据时,上述解决方案才能正常工作,否则将删除多行.
WARNING The solution above will only work correctly if the 2nd column contains unique data, otherwise multiple rows would be deleted.
还有一个假设,即删除有效,最好拥有:-
There is also the assumption that the deletion works, it could be better to have :-
@Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { if (myDb.deleteRow((String)fachListAdapter.getItem(position))<0) { faecherListe.remove(position); } fachListAdapter.notifyDataSetChanged(); return true; //<<<< Indicate that this longclick has been used }
游标适配器方法
但是,还有其他一些适用于游标的适配器,这些适配器可以消除对中间Array的需求.您可以使用
CursorAdapter
.对于CursorAdapter
,列名称为_id
是必需的,此列应为 long ,并且也不能唯一地标识该行.目的和因此的名称是使用 rowid 的别名(因此也存在为什么存在CONSTANTBaseColumns._ID
的原因).Cursor Adapter method
However, there are other adaptors suited to Cursors that could do away with the need for an intermediate Array. You could utilise a
CursorAdapter
. For aCursorAdapter
a column name_id
is required and this column should be a long and also unqiuely identify the row. The intention and hence the name is that an alias of the rowid is used (hence also why the CONSTANTBaseColumns._ID
exists).通过定义
?? INTEGER PRIMARY KEY
其中??来创建 rowid 的别名.是列名.因此,理想情况下,应定义表格,并使用_id INTEGER PRIMARY KEY
列定义.CREATE mytable (_id INTEGER PRIMARY KEY, myothercolumn TEXT)
(您可以在INTEGER PRIMARY KEY
后面加上关键字AUTOINCREMENT,但是通常不会这样做,因为它有开销An alias of the rowid is created by defining
?? INTEGER PRIMARY KEY
where ?? is the column name. So ideally the table should be defined including a column definition with_id INTEGER PRIMARY KEY
e.g.CREATE mytable (_id INTEGER PRIMARY KEY, myothercolumn TEXT)
(you can followINTEGER PRIMARY KEY
with the keyword AUTOINCREMENT, however generally you would not do so, as it has overheads SQLite Autoincrement)如果表中没有这样的列,那么在查询数据时,您总是可以使用
rowid AS _id
在游标中创建一列,例如如果SQL等于SELECT * FROM mytable
,则可以使用SELECT *, rowid AS _id FROM mytable
.If your table does not have such a column then you can always create a column in the cursor when querying the data, by using
rowid AS _id
e.g. if you SQL equates toSELECT * FROM mytable
then you can useSELECT *, rowid AS _id FROM mytable
.在此示例中,将使用库存
SimpleCursorAdapter
,代码可能为:-In this example the stock
SimpleCursorAdapter
will be used, the code could be :-public class ZeigeFaecherListe extends AppCompatActivity { DatabaseHelper myDb; Cursor res; ListView listViewFaecher; SimpleCursorAdapter fachSimpleCursorAdapter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.zeige_faecher); listViewFaecher = (ListView) this.findViewById(R.id.listview); myDb = new DatabaseHelper(this); addSomeData(); //<<<<<<<<<< ADDED for testing faecherListe = new ArrayList<>(); res = myDb.zeigeFaecher(); fachSimpleCursorAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, //<<<< The layout res, //<<<< The Cursor new String[]{"_data"}, //<<<< The column names from which to get the data new int[]{android.R.id.text1} //<<<< The ids of the views in which the data is placed ); listViewFaecher.setAdapter(fachSimpleCursorAdapter); listViewFaecher.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { // id is the value of the respective _id column //<<<< Normally you would have the delete method in the Databasehelper >>>> myDb.getWritableDatabase().delete("mytable","_id=?",new String[]{String.valueOf(id)}); fachSimpleCursorAdapter.swapCursor(myDb.zeigeFaecher()); // Tell the adapter about the new cursor return true; } }); } }
注意,因为
_id
列将始终是唯一的.如果显示的值不是唯一的,此方法将只删除特定行而不删除多行.NOTE as the
_id
column will always be unique this method will only delete the specific row not multiple rows if the displayed values are not unique.这篇关于使用OnItemClickListener从ListView和数据库中删除项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!