En resumen, debe poder distinguir una fila para su eliminación por los datos disponibles para ListView. Si el valor recuperado del cursor, como la segunda columna (es decir, la cadena extraída usando res.getString(1))
, y el valor va a ser único , puede recuperarlo y usarlo para la eliminación.
Sin embargo, hay algunos problemas al usar un ListAdapter
probablemente no será suficiente. Hay otros adaptadores, como un ArrayAdapter que ofrece más funciones y, lo que es más importante, un notifyDatasetChanged
(que actualizará el ListView asociado).
Es un desperdicio crear un nuevo adaptador para cada iteración del cursor. Por lo tanto, el adaptador debe crearse fuera del bucle y solo una vez.
Sugeriría que la eliminación en el clic del elemento será demasiado propensa a hacer clic accidentalmente, la eliminación en el elemento LongClick sería mucho menos propensa a la eliminación accidental.
Si mueve variables para que sean variables de clase, no tiene que declararlas como finales.
Entonces, según lo anterior, podría tener:-
Método del adaptador de matriz
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));
}
}
}
Junto con lo anterior, deletRow
el método es:-
public int deleteRow(String col2) {
SQLiteDatabase db = this.getWritableDatabase();
return db.delete(TB001,COL_TB001_DATA + "=?",new String[]{col2});
}
- dónde
TB001 es una cadena constante que se establece en el nombre de la tabla.COL_TB001_DATA es el nombre de columna de la segunda columna.
ADVERTENCIA La solución anterior solo funcionará correctamente si la segunda columna contiene datos únicos; de lo contrario, se eliminarían varias filas.
También existe la suposición de que la eliminación funciona, podría ser mejor tener :-
@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
}
Método de adaptador de cursor
Sin embargo, existen otros adaptadores adecuados para cursores que podrían eliminar la necesidad de una matriz intermedia. Podría utilizar un CursorAdapter
. Para un CursorAdapter
un nombre de columna _id
es obligatorio y esta columna debe ser larga y también identificar de forma unqiuely la fila. La intención y por lo tanto el nombre es que un alias de rowid se utiliza (de ahí también por qué CONSTANT BaseColumns._ID
existe).
Un alias del rowid se crea definiendo ?? INTEGER PRIMARY KEY
donde ?? es el nombre de la columna. Entonces, idealmente, la tabla debería definirse incluyendo una definición de columna con _id INTEGER PRIMARY KEY
p.ej. CREATE mytable (_id INTEGER PRIMARY KEY, myothercolumn TEXT)
(puedes seguir INTEGER PRIMARY KEY
con la palabra clave AUTOINCREMENT, sin embargo, generalmente no lo haría, ya que tiene gastos generales SQLite Autoincrement)
Si su tabla no tiene esa columna, siempre puede crear una columna en el cursor al consultar los datos, usando rowid AS _id
p.ej. si SQL equivale a SELECT * FROM mytable
entonces puedes usar SELECT *, rowid AS _id FROM mytable
.
En este ejemplo, el stock SimpleCursorAdapter
se utilizará, el código podría ser:-
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 como el _id
la columna siempre será única; este método solo eliminará la fila específica, no varias filas, si los valores mostrados no son únicos.