SQLite
 sql >> Base de données >  >> RDS >> SQLite

Suppression d'un élément de ListView et de la base de données avec OnItemClickListener

En bref, vous devez être en mesure de distinguer une ligne à supprimer par les données disponibles pour le ListView. Si la valeur extraite du curseur, comme la 2ème colonne (c'est-à-dire la chaîne extraite en utilisant res.getString(1)) , et la valeur devient unique , vous pouvez le récupérer et l'utiliser pour la suppression.

Cependant, il y a quelques problèmes, en utilisant un ListAdapter ne suffira probablement pas. Il existe d'autres adaptateurs, tels qu'un ArrayAdapter qui offrent plus de fonctionnalités et surtout un notifyDatasetChanged méthode (qui actualisera le ListView associé).

C'est un gaspillage de créer un nouvel adaptateur pour chaque itération du curseur. L'adaptateur doit donc être créé en dehors de la boucle et une seule fois.

Je dirais que la suppression d'un clic sur un élément sera trop sujette à un clic accidentel, la suppression d'un élément LongClick serait beaucoup moins sujette à une suppression accidentelle.

Si vous déplacez des variables pour en faire des variables de classe, vous n'avez pas besoin de les déclarer comme finales.

Donc, sur la base de ce qui précède, vous pourriez avoir :-

Méthode de l'adaptateur de tableau

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

Avec ce qui précède, le deletRow la méthode est :-

public int deleteRow(String col2) {
    SQLiteDatabase db = this.getWritableDatabase();
    return db.delete(TB001,COL_TB001_DATA + "=?",new String[]{col2});
}
    • TB001 est une chaîne constante définie sur le nom de la table.
    • COL_TB001_DATA est le nom de colonne de la 2ème colonne.

AVERTISSEMENT La solution ci-dessus ne fonctionnera correctement que si la 2ème colonne contient des données uniques, sinon plusieurs lignes seraient supprimées.

Il y a aussi l'hypothèse que la suppression fonctionne, il pourrait être préférable d'avoir :-

        @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éthode de l'adaptateur de curseur

Cependant, il existe d'autres adaptateurs adaptés aux curseurs qui pourraient éliminer le besoin d'un tableau intermédiaire. Vous pouvez utiliser un CursorAdapter . Pour un CursorAdapter un nom de colonne _id est obligatoire et cette colonne doit être longue et également identifier de manière univoque la ligne. L'intention et donc le nom est qu'un alias du rowid est utilisé (d'où aussi pourquoi la CONSTANTE BaseColumns._ID existe).

Un alias du rowid est créé en définissant ?? INTEGER PRIMARY KEY où ?? est le nom de la colonne. Donc, idéalement, la table devrait être définie en incluant une définition de colonne avec _id INTEGER PRIMARY KEY par exemple. CREATE mytable (_id INTEGER PRIMARY KEY, myothercolumn TEXT) (vous pouvez suivre INTEGER PRIMARY KEY avec le mot-clé AUTOINCREMENT, mais généralement vous ne le feriez pas, car il a des frais généraux SQLite Autoincrement)

Si votre table n'a pas une telle colonne, vous pouvez toujours créer une colonne dans le curseur lors de l'interrogation des données, en utilisant rowid AS _id par exemple. si vous SQL équivaut à SELECT * FROM mytable alors vous pouvez utiliser SELECT *, rowid AS _id FROM mytable .

Dans cet exemple, le stock SimpleCursorAdapter sera utilisé, le code pourrait être :-

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

REMARQUE comme _id la colonne sera toujours unique cette méthode ne supprimera que la ligne spécifique et non plusieurs lignes si les valeurs affichées ne sont pas uniques.