In breve, è necessario essere in grado di distinguere una riga da eliminare in base ai dati disponibili in ListView. Se il valore recuperato dal cursore, come 2a colonna (ovvero la String estratta usando res.getString(1))
, e il valore diventerà unico , puoi recuperarlo e usarlo per l'eliminazione.
Tuttavia, ci sono alcuni problemi, usando un ListAdapter
probabilmente non sarà sufficiente. Esistono altri adattatori, come un ArrayAdapter che offrono più funzionalità e soprattutto un notifyDatasetChanged
metodo (che aggiornerà il ListView associato).
È uno spreco creare un nuovo adattatore per ogni iterazione del cursore. Quindi l'adattatore dovrebbe essere creato al di fuori del loop e solo una volta.
Suggerirei che l'eliminazione del clic sull'elemento sarà troppo soggetta a clic accidentali, l'eliminazione dell'elemento LongClick sarebbe molto meno soggetta all'eliminazione accidentale.
Se sposti le variabili come variabili di classe non devi dichiararle come finali.
Quindi, in base a quanto sopra, potresti avere :-
Metodo dell'adattatore array
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));
}
}
}
Insieme a quanto sopra, il deletRow
il metodo è :-
public int deleteRow(String col2) {
SQLiteDatabase db = this.getWritableDatabase();
return db.delete(TB001,COL_TB001_DATA + "=?",new String[]{col2});
}
- dove
- TB001 è una stringa costante impostata sul nome della tabella.
- COL_TB001_DATA è il nome della colonna della seconda colonna.
AVVISO La soluzione sopra funzionerà correttamente solo se la seconda colonna contiene dati univoci, altrimenti più righe verrebbero eliminate.
C'è anche il presupposto che la cancellazione funzioni, potrebbe essere meglio avere :-
@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
}
Metodo adattatore cursore
Tuttavia, esistono altri adattatori adatti ai cursori che potrebbero eliminare la necessità di un array intermedio. Potresti utilizzare un CursorAdapter
. Per un CursorAdapter
un nome di colonna _id
è obbligatorio e questa colonna deve essere lunga e anche identificare in modo inequivocabile la riga. L'intenzione e quindi il nome è un alias di rowid viene utilizzato (quindi anche perché il CONSTANT BaseColumns._ID
esiste).
Un alias di rowid viene creato definendo ?? INTEGER PRIMARY KEY
dove ?? è il nome della colonna. Quindi idealmente la tabella dovrebbe essere definita includendo una definizione di colonna con _id INTEGER PRIMARY KEY
per esempio. CREATE mytable (_id INTEGER PRIMARY KEY, myothercolumn TEXT)
(puoi seguire INTEGER PRIMARY KEY
con la parola chiave AUTOINCREMENT, tuttavia generalmente non lo faresti, in quanto ha overhead SQLite Autoincrement)
Se la tua tabella non ha una tale colonna, puoi sempre creare una colonna nel cursore quando esegui query sui dati, usando rowid AS _id
per esempio. se SQL equivale a SELECT * FROM mytable
quindi puoi usare SELECT *, rowid AS _id FROM mytable
.
In questo esempio lo stock SimpleCursorAdapter
verrà utilizzato, il codice potrebbe essere :-
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;
}
});
}
}
NOTA come _id
la colonna sarà sempre univoca questo metodo eliminerà solo la riga specifica e non più righe se i valori visualizzati non sono univoci.