SQLite
 sql >> Datenbank >  >> RDS >> SQLite

Element aus ListView und Datenbank mit OnItemClickListener löschen

Kurz gesagt, Sie müssen in der Lage sein, eine zu löschende Zeile anhand der für die ListView verfügbaren Daten zu unterscheiden. Wenn der Wert vom Cursor abgerufen wird, als zweite Spalte (d. h. der String, der mit res.getString(1)) extrahiert wurde , und der Wert wird eindeutig sein , können Sie diese abrufen und für die Löschung verwenden.

Es gibt jedoch einige Probleme bei der Verwendung eines ListAdapter wird wohl nicht reichen. Es gibt andere Adapter, wie z. B. einen ArrayAdapter, der mehr Funktionen bietet, und vor allem ein notifyDatasetChanged -Methode (die die zugehörige ListView aktualisiert).

Es ist eine Verschwendung, für jede Iteration des Cursors einen neuen Adapter zu erstellen. Der Adapter sollte also außerhalb der Schleife und nur einmal erstellt werden.

Ich würde vorschlagen, dass das Löschen auf Elementklick zu anfällig für versehentliches Klicken ist, das Löschen auf Element LongClick wäre weitaus weniger anfällig für versehentliches Löschen.

Wenn Sie Variablen in Klassenvariablen verschieben, müssen Sie sie nicht als endgültig deklarieren.

Basierend auf dem oben Gesagten könnten Sie also Folgendes haben:-

Array-Adapter-Methode

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));
        }
    }
}

Zusammen mit dem obigen deletRow Methode ist:-

public int deleteRow(String col2) {
    SQLiteDatabase db = this.getWritableDatabase();
    return db.delete(TB001,COL_TB001_DATA + "=?",new String[]{col2});
}
  • wo
    • TB001 ist ein konstanter String, der auf den Namen der Tabelle gesetzt wird.
    • COL_TB001_DATA ist der Spaltenname der 2. Spalte.

WARNUNG Die obige Lösung funktioniert nur dann korrekt, wenn die 2. Spalte eindeutige Daten enthält, da sonst mehrere Zeilen gelöscht würden.

Es gibt auch die Annahme, dass das Löschen funktioniert, es könnte besser sein, :-

zu haben
        @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
        }

Cursor-Adapter-Methode

Es gibt jedoch andere für Cursor geeignete Adapter, die die Notwendigkeit eines Zwischenarrays überflüssig machen könnten. Sie könnten einen CursorAdapter verwenden . Für einen CursorAdapter ein Spaltenname _id ist erforderlich und diese Spalte sollte lang sein und auch eindeutig die Zeile identifizieren. Die Absicht und daher der Name ist, dass ein Alias ​​der rowid verwendet wird (daher auch die Konstante BaseColumns._ID existiert).

Ein Alias ​​der rowid wird durch die Definition von ?? INTEGER PRIMARY KEY wo ?? ist der Spaltenname. Idealerweise sollte die Tabelle also inklusive einer Spaltendefinition mit _id INTEGER PRIMARY KEY definiert werden z.B. CREATE mytable (_id INTEGER PRIMARY KEY, myothercolumn TEXT) (Sie können INTEGER PRIMARY KEY folgen mit dem Schlüsselwort AUTOINCREMENT, aber im Allgemeinen würden Sie dies nicht tun, da es Overheads von SQLite Autoincrement hat)

Wenn Ihre Tabelle keine solche Spalte hat, können Sie beim Abfragen der Daten immer eine Spalte im Cursor erstellen, indem Sie rowid AS _id verwenden z.B. wenn Sie SQL mit SELECT * FROM mytable gleichsetzen dann können Sie SELECT *, rowid AS _id FROM mytable verwenden .

In diesem Beispiel der vorrätige SimpleCursorAdapter verwendet wird, könnte der Code :-

sein
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;
            }
        });
    }
}

HINWEIS als _id Spalte ist immer eindeutig. Diese Methode löscht nur die spezifische Zeile, nicht mehrere Zeilen, wenn die angezeigten Werte nicht eindeutig sind.