SQLite
 sql >> Database >  >> RDS >> SQLite

Eliminazione di elementi da ListView e Database con OnItemClickListener

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.