Skip to content Skip to sidebar Skip to footer

Deleting Item From Listview And Database With Onitemclicklistener

I created a database and managed to display the added items into a ListView. Now I need a method to delete an item from the ListView and the Database. public class ZeigeFaecherLis

Solution 1:

In short, you need to be able to distinguish a row for deletion by the data available to the ListView. If the value retrieved from the cursor, as the 2nd column (i.e. the String extracted by using res.getString(1)), and the value is going the be unique, you can retrieve this and use it for the deletion.

However, there are a few issues, using a ListAdapter will probably not be sufficient. There are other adapters, such as an ArrayAdapter that offer more features and importantly a notifyDatasetChanged method (that will refresh the associated ListView).

It is a waste to create a new adapter for each iteration of the cursor. So the adapter should be created outside of the loop and just the once.

I'd suggest that deleting on item click will be too prone to accidental clicking, deleting on item LongClick would be far less prone to accidental deletion.

If you move variables to be class variables you don't have to declare them as final.

So based upon the above, you could have :-

Array Adapter method

publicclassZeigeFaecherListeextendsAppCompatActivity {

    DatabaseHelper myDb;
    Cursor res;
    ListView listViewFaecher;
    ArrayAdapter<String> fachListAdapter;
    ArrayList<String> faecherListe;

    @OverrideprotectedvoidonCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.zeige_faecher);

        listViewFaecher = (ListView) this.findViewById(R.id.listview);
        myDb = newDatabaseHelper(this);
        addSomeData(); //<<<<<<<<<< ADDED for testing

        faecherListe = newArrayList<>();
        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 = newArrayAdapter<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(newAdapterView.OnItemLongClickListener() {
            @OverridepublicbooleanonItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                myDb.deleteRow((String)fachListAdapter.getItem(position));
                faecherListe.remove(position);
                fachListAdapter.notifyDataSetChanged(); 
                returntrue; //<<<< Indicate that this longclick has been used
            }
        });
    }

    privatevoidaddSomeData() {
        for (int i=1; i <= 10; i++) {
            myDb.addRow("Row " + String.valueOf(i));
        }
    }
}

Along with the above the deletRow method is :-

public int deleteRow(String col2) {
    SQLiteDatabase db = this.getWritableDatabase();
    return db.delete(TB001,COL_TB001_DATA + "=?",newString[]{col2});
}
  • where
    • TB001 is a constant String thatis set to the table's name.
    • COL_TB001_DATA is the column name of the 2nd column.

WARNING The solution above will only work correctly if the 2nd column contains unique data, otherwise multiple rows would be deleted.

There is also the assumption that the deletion works, it could be better to have :-

@OverridepublicbooleanonItemLongClick(AdapterView<?> parent, View view, int position, long id) {
            if (myDb.deleteRow((String)fachListAdapter.getItem(position))<0) {
                faecherListe.remove(position);
            }
            fachListAdapter.notifyDataSetChanged(); 
            returntrue; //<<<< Indicate that this longclick has been used
        }

Cursor Adapter method

However, there are other adaptors suited to Cursors that could do away with the need for an intermediate Array. You could utilise a CursorAdapter. For a CursorAdapter a column name _id is required and this column should be a long and also unqiuely identify the row. The intention and hence the name is that an alias of the rowid is used (hence also why the CONSTANT BaseColumns._ID exists).

An alias of the rowid is created by defining ?? INTEGER PRIMARY KEY where ?? is the column name. So ideally the table should be defined including a column definition with _id INTEGER PRIMARY KEY e.g. CREATE mytable (_id INTEGER PRIMARY KEY, myothercolumn TEXT)(you can follow INTEGER PRIMARY KEY with the keyword AUTOINCREMENT, however generally you would not do so, as it has overheads SQLite Autoincrement)

If your table does not have such a column then you can always create a column in the cursor when querying the data, by using rowid AS _id e.g. if you SQL equates to SELECT * FROM mytable then you can use SELECT *, rowid AS _id FROM mytable.

In this example the stock SimpleCursorAdapter will be used, the code could be :-

publicclassZeigeFaecherListeextendsAppCompatActivity {

    DatabaseHelper myDb;
    Cursor res;
    ListView listViewFaecher;
    SimpleCursorAdapter fachSimpleCursorAdapter;

    @OverrideprotectedvoidonCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.zeige_faecher);

        listViewFaecher = (ListView) this.findViewById(R.id.listview);
        myDb = newDatabaseHelper(this);
        addSomeData(); //<<<<<<<<<< ADDED for testing

        faecherListe = newArrayList<>();
        res = myDb.zeigeFaecher();
        fachSimpleCursorAdapter = newSimpleCursorAdapter(this,
                android.R.layout.simple_list_item_1, //<<<< The layout
                res, //<<<< The CursornewString[]{"_data"}, //<<<< The column names from which to get the datanew int[]{android.R.id.text1} //<<<< The ids of the views in which the data is placed
                );
        listViewFaecher.setAdapter(fachSimpleCursorAdapter);
        listViewFaecher.setOnItemLongClickListener(newAdapterView.OnItemLongClickListener() {
            @OverridepublicbooleanonItemLongClick(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=?",newString[]{String.valueOf(id)});
                fachSimpleCursorAdapter.swapCursor(myDb.zeigeFaecher()); // Tell the adapter about the new cursorreturntrue;
            }
        });
    }
}

NOTE as the _id column will always be unique this method will only delete the specific row not multiple rows if the displayed values are not unique.

Solution 2:

listViewFaecher.setOnItemClickListener(newAdapterView.OnItemClickListener() {
    @OverridepublicvoidonItemClick(AdapterView<?> adapterView, View view, int position, long id) {

         // Call delete method here by passing position//position will contain the position of item clicked by the user.
     }
});

Post a Comment for "Deleting Item From Listview And Database With Onitemclicklistener"