Накратко, трябва да можете да различите ред за изтриване по данните, налични за ListView. Ако стойността е извлечена от курсора, като 2-ра колона (т.е. низът, извлечен с помощта на res.getString(1))
,и стойността ще бъде уникална , можете да извлечете това и да го използвате за изтриването.
Има обаче няколко проблема при използване на ListAdapter
вероятно няма да е достатъчно. Има и други адаптери, като ArrayAdapter, които предлагат повече функции и най-важното notifyDatasetChanged
метод (който ще опресни свързания ListView).
Създаването на нов адаптер за всяка итерация на курсора е загуба. Така че адаптерът трябва да бъде създаден извън цикъла и само веднъж.
Предполагам, че изтриването на щракване върху елемент ще бъде твърде податливо на случайно щракване, изтриването на елемент LongClick би било далеч по-малко податливо на случайно изтриване.
Ако преместите променливи, за да бъдат променливи на клас, не е нужно да ги декларирате като окончателни.
Така че въз основа на горното, можете да имате :-
Метод на адаптера на масив
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
методът е :-
public int deleteRow(String col2) {
SQLiteDatabase db = this.getWritableDatabase();
return db.delete(TB001,COL_TB001_DATA + "=?",new String[]{col2});
}
- къде
- TB001 е константен низ, който е зададен на името на таблицата.
- COL_TB001_DATA е името на колоната на 2-ра колона.
ПРЕДУПРЕЖДЕНИЕ Решението по-горе ще работи правилно само ако 2-та колона съдържа уникални данни, в противен случай множество редове ще бъдат изтрити.
Има също така предположението, че изтриването работи, може да е по-добре да имате :-
@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
}
Метод на адаптера на курсора
Има обаче и други адаптери, подходящи за курсори, които могат да премахнат необходимостта от междинен масив. Можете да използвате CursorAdapter
. За CursorAdapter
име на колона _id
е задължителен и тази колона трябва да е дълга и също така неправилно идентифициране на реда. Намерението и оттам името е псевдоним на rowid се използва (следователно и защо CONSTANT BaseColumns._ID
съществува).
Псевдоним на rowid се създава чрез дефиниране на ?? INTEGER PRIMARY KEY
където ?? е името на колоната. Така че в идеалния случай таблицата трябва да бъде дефинирана, включително дефиниция на колона с _id INTEGER PRIMARY KEY
напр. CREATE mytable (_id INTEGER PRIMARY KEY, myothercolumn TEXT)
(можете да следвате INTEGER PRIMARY KEY
с ключовата дума AUTOINCREMENT, но обикновено не бихте го направили, тъй като има допълнителни разходи за SQLite Autoincrement)
Ако вашата таблица няма такава колона, винаги можете да създадете колона в курсора при запитване на данните, като използвате rowid AS _id
напр. ако SQL се равнява на SELECT * FROM mytable
тогава можете да използвате SELECT *, rowid AS _id FROM mytable
.
В този пример стандартният SimpleCursorAdapter
ще се използва, кодът може да бъде :-
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
колоната винаги ще бъде уникална, този метод ще изтрие само конкретния ред, а не множество редове, ако показаните стойности не са уникални.