sql >> Base de Datos >  >> RDS >> SQLite

Eliminación de elementos de ListView y base de datos con OnItemClickListener

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.