I have a listview that gets the data from an Arraylist and this Arraylist gets data from a database. Now I want to delete an item from the listview and also I want to delete this record from database. In addition, the delete option is in a contextmenu. I just want to know how to send the record's Id to the listview items and also the delete method in the dataModel. I can have the ID by reslist.getId()
Here is getView and contextmenu:
public View getView(int i, View view, ViewGroup viewGroup) {
View v = view;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.list_layout, null);
}
TextView tv1 = (TextView) v.findViewById(R.id.resName);
TextView tv2 = (TextView) v.findViewById(R.id.resAddress);
ImageView iv = (ImageView) v.findViewById(R.id.resType);
tv1.setText(resList.get(i).getName());
tv2.setText(resList.get(i).getAddress());
iv.setImageResource(R.drawable.tpng);
if(resList.get(i).getType().equals("takeaway")){
iv.setImageResource(R.drawable.tpng);
}else if(resList.get(i).getType().equals("delivery")){
iv.setImageResource(R.drawable.dpng);
}else if(resList.get(i).getType().equals("sitdown")){
iv.setImageResource(R.drawable.spng);
}
registerForContextMenu(v);
return v;
}
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
getMenuInflater().inflate(R.menu.list_menu, menu);
super.onCreateContextMenu(menu, v, menuInfo);
}
public boolean onContextItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.remove:
// I should use delete method here and I just want Item Id
break;
case R.id.item2:
break;
}
return super.onContextItemSelected(item);
}
and this is the delete method in dataModel
public void deleteRestaurant(int id){
SQLiteDatabase db = getWritableDatabase();
db.execSQL("DELETE FROM " + TABLE_RESTAURANT + "WHERE" + KEY_ID + " = ?", new String[] {String.valueOf(id)});
}
To delete a record from the sqlite database , you can use the following code :
public void deleteRestaurant(int id) {
System.out.println("the deleted restaurant has the id: " + id);
SQLiteDatabase db = getWritableDatabase();
db.delete(TABLE_RESTAURANT, KEY_ID + " = " + id, null);
}
Check this full tutorial about how to use SQLite Database with Multiple Tables in Android
If you use a CursorLoader with your Adapter, all you have to do is delete the row in the database and the rest will happen automatically.
Here is a link: Loaders
you need to get the position of the selected item. then remove item from your Array list. Once you have removed the item, call the notifyDataSetChanged method then it will automatically remove the view.
switch(item.getItemId()){
case R.id.remove:
// I should use delete method here and I just want Item Id
deleteRestaurant(id);
arrayList.remove(position);
notifyDataSetChanged();
break;
case R.id.item2:
break;
Related
I am trying to obtain the database row id from the listview item in onItemClickListener when using a custom adapter.
I have tried getting the id from the "long id" inside of the onItemClickListener but it seems to return just the row id of the item in the actual list, not the database row id.
Here is my onItemClickListener:
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
String selected = (String)
mListView.getItemAtPosition(position);
mTextView = findViewById(R.id.Words);
mNumberTextView = findViewById(R.id.Number);
mId = id;
mAdapterView = adapterView;
mPositionForRow = position;
mCopied =
mHeaderNameTextView.getText().toString();
mNumberCopied = Integer.toString(mSelected + 1);
mNumberCopied =
mNumberTextView.getText().toString();
mPosition = position + 1;
mCopiedListItem = mBookCopied + " " +
mNumberCopied + ":" + mPosition + "\n\n" + selected;
showMenu(view);
}
});
Here is my custom adapter:
public Adapter(Context context, int resource1, List<String> lines) {
super(context, resource1, lines);
this.mContext = context;
this.mResource1 = resource1;
this.mLines = lines;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull
ViewGroup parent) {
View listItem = convertView;
int pos = position + 1;
if (listItem == null) {
listItem = LayoutInflater.from(mContext).inflate(mResource1,
parent, false);
}
mNumberTextView = (TextView)
listItem.findViewById(R.id.Number);
mNumberTextView.setText(String.valueOf(pos) + " ");
mTextView = (TextView) listItem.findViewById(R.id.Words);
mTextView.setText(mLines.get(position));
}
return listItem;
}
}
When a list item is clicked on, a menu pops up. If the user selects "select item", it should get the actual database row id from the item click but it returns the list item number which is not what I need. I also convert the long to an int in the process. I just didn't see a need to include that method.
Here is that menu option:
case R.id.select_item:
Log.d("TAG", "mId =" + mId);
mRowPositionInt = (safeLongToInt(mId));
updateData(1, mRowPositionInt);
Log.d("TAG", "mRowPosition =" + mRowPositionInt);
mSharedPreferences.edit().putInt("RowPositionSqlite",
mRowPositionInt).apply();
Toast toast2 = Toast.makeText(getApplicationContext(),
"Select Item Button Clicked!", Toast.LENGTH_SHORT);
toast2.show();
}
There are no error messages it just does not return the actual database row id. Any advice would be helpful. I have been through other posts but not applied to my situation. I appreciate your help.
The long id you get back is the long you return from your adapter's getItemId().
If you want a database row id to be return rather than just the position, you need to:
Pass in the database row ids to your adapter
Have getItemId() return the correct id for the given position.
On deleting the item from the Listview the item gets deleted at that time, but on coming back to the activity the item reappears.
This is my Main2Activity code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
position = intent.getIntExtra("position", 0);
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, listItem);
listView.setAdapter(adapter);
viewData1();
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, final int pos, long id) {
final int itemToDelete = pos;
new AlertDialog.Builder(Main2Activity.this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle("Are you sure?")
.setMessage("Do you want to delete this location?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
listItem.remove(itemToDelete);
databaseHelper1.deleteLocation(itemToDelete, position);
adapter.notifyDataSetChanged();
}
}
)
.setNegativeButton("No", null)
.show();
return true;
}
});
}
private void viewData1() {
Cursor cursor = databaseHelper1.viewData1(position);
if (cursor.getCount() == 0) {
Toast.makeText(this, "No data to show", Toast.LENGTH_SHORT).show();
} else {
while (cursor.moveToNext()) {
Log.i("message", "Data got");
listItem.add(cursor.getString(1));
}
adapter.notifyDataSetChanged();
}
}
DatabaseHelper:
public void deleteLocation(int itemToDelete,int position)
{
SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
String itemDelete = Integer.toString(itemToDelete);
Log.i("itemdel",itemDelete);
if(position ==0)
{
String Id = (ID1);
Log.i("Id",Id);
String query = " Delete from "+DB_TABLE1 + " where "+ Id + " = " + itemDelete;
sqLiteDatabase.execSQL(query);
sqLiteDatabase.delete(DB_TABLE1,ID1 + " = "+ itemDelete, null);
sqLiteDatabase.compileStatement(query);
Log.i("del"," executed")
}
}
public Cursor viewData1(int position)
{
SQLiteDatabase sqLiteDatabase = this.getReadableDatabase();
Cursor cursor = null;
if (position ==0)
{
String query = "Select * from " + DB_TABLE1;
cursor = sqLiteDatabase.rawQuery(query, null);
}
return cursor;
}
What happens is:
Before Deleting:
After Deleting garden:
On restarting activity:
How do I commit the delete to the database? Thanks.
Your issue is that you are assuming that position (3rd parameter passed to the onItemLongClick method) directly relates to the id of the row.
You cannot rely on a correlation between position and id.
The first position in the list will be at position 0. The lowest ID allocated (unless forced) will be 1. However adding 1 is not a solution as even though it may initially work. As soon as you delete anything other than the last item in the list then an id is omitted from the list of id's and you may not delete a row or you may delete a different row.
The most sensible/easiest fix is to utilise a CursorAdapter i.e. SimpleCursorAdapter in which case the 4th parameter to onItemClick and onItemLongClick (long l) will be the actual id. However, to utilise a CursorAdapter you MUST have the id column named as _id (hence why there is the constant BaseColumns._ID).
You could always rename the column when extracting it using AS e.g. SELECT rowid AS _id, * FROM the_table; (which will select all existing columns AND the id column).
Here's a link to a more comprehensive answer with options for other adapter Deleting item from ListView and Database with OnItemClickListener
I have created a database which is displayed in a ListView using an ArrayAdapter. I want a selected ListView item to be deleted when a ContextMenu pops up with a delete option as depicted below:
I have a class for handling all the database functions like delete. When I use a normal onCLicklistener with a button, the delete function is performed correctly, i.e it deletes the correct database entry and reaches the if (cursor.moveToFirst()) line. When I make use of the delete menu item, it does not reach the if (cursor.moveToFirst()) line in the attached delete handler function and therefore does not delete the entry (attached after the ListView code snippet below is the delete handler).
Any help/guidance/examples will be greatly appreciated.
My ListView is populated as follows:
public class Listview extends AppCompatActivity
{
private ListView users;
FloatingActionButton fab;
MyDBHandler dbHandler;
ArrayAdapter<String> arrayAdapter;
String lists;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
setContentView(R.layout.activity_listview);
// Create back button in action bar
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
users = (ListView) findViewById(R.id.clientlst);
// Floating Action bar for adding new data entries
fab = (FloatingActionButton) findViewById(R.id.fab1);
MyDBHandler dbHandler = new MyDBHandler(getApplicationContext());
lists = dbHandler.loadHandler();
//Create a list of the saved database String array items and split into
Strings
ArrayList<String> list = new ArrayList<>
(Arrays.asList(lists.split("\n")));
// Create the List view adapter
arrayAdapter = new ArrayAdapter<String>(Listview.this,
android.R.layout.simple_list_item_1, android.R.id.text1, list)
{
#Override // Edit the Text colour of the Listview items
public View getView(int position, View convertView, ViewGroup parent)
{
String Items = arrayAdapter.getItem(position);
String[] separated = Items.split(":");
String Name123 = separated[1]; // This will contain "Name"
TextView textView = (TextView) super.getView(position,
convertView, parent);
textView.setTextColor(Color.BLUE);
textView.setText(Name123);
return textView;
}
};
users.setAdapter(arrayAdapter);
registerForContextMenu(users);
// Create an action to be performed by each click of an item in the
users.setOnItemClickListener
(
new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View
view, int position, long id) {
String Items = arrayAdapter.getItem(position);
String[] separated = Items.split(":");
String ip = separated[5]; // This will contain "PORT address"
String port = separated[3]; // This will contain "IP number"
Toast.makeText(Listview.this, port + ip,
Toast.LENGTH_LONG).show();
} // onItemClick
} // OnItemClickListener View
); // OnItemClickListener
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view)
{
Toast.makeText(Listview.this, "Fab
Clicked", Toast.LENGTH_LONG).show();
}
}
);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderTitle("Choose an option");
MenuInflater inflator = getMenuInflater();
inflator.inflate(R.menu.example_menu, menu);
}
#Override
public boolean onContextItemSelected(MenuItem item)
{
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId())
{
case R.id.option_1:
arrayAdapter.getItem(info.position);
MyDBHandler dbHandler = new MyDBHandler(getApplicationContext());
String Items= arrayAdapter.getItem(info.position);
String[] separated = Items.split(":");
String ip = separated[3]; // This will
contain "IP addr"
String names = separated[1]; // This will
contain "Name"
Log.d("LATE",names + ip);
dbHandler.deleteHandler(names,ip);
arrayAdapter.notifyDataSetChanged(); // Refresh the
listview
Toast.makeText(this, "Deleted", Toast.LENGTH_SHORT).show();
Intent listviews1 = new Intent(Listview.this, Listview.class);
startActivity(listviews1);
return true;
case R.id.option_2:
Intent listviews2 = new Intent(Listview.this, Listview.class);
startActivity(listviews2);
Toast.makeText(this, "Updated", Toast.LENGTH_SHORT).show();
return true;
default:
return super.onContextItemSelected(item);
}
}
}
The delete handler function of the database is as follows:
public void deleteHandler(String username, String IP)
{
//boolean result = false;
String query = "Select*FROM " + TABLE_USER + " WHERE " + COLUMN_NAME + "
= '" + String.valueOf(username) + "'" + " and " + COLUMN_ID + " = '" +
String.valueOf(IP) + "'";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
Log.d ("MEH", String.valueOf(cursor));
User user = new User();
if (cursor.moveToFirst())
{
user.setUserName(cursor.getString(2));
user.setID(cursor.getString(3));
db.delete(TABLE_USER, COLUMN_NAME + "=? and " + COLUMN_ID + "=?",
new String[]
{
String.valueOf(user.getUserName()),
String.valueOf(user.getID())
});
cursor.close();
//result = true;
}
db.close();
//return result;
}
You aren't calling any method to delete the item from the database from your users.setOnItemClickListener
As you added in your comment, all you are doing is trying to delete the item from your ActionBar's onItemClicked method.
Do the same inside your OnItemClickListener
Update2: Change in requirement
users.setLongClickable(true);
users.setOnItemLongClickListener(new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) {
//Do your tasks here
AlertDialog.Builder alert = new AlertDialog.Builder(
YourActivity.this);
alert.setTitle("Alert!!");
alert.setMessage("Choose an option");
alert.setPositiveButton("Edit", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//do your work here
dialog.dismiss();
}
});
alert.setNegativeButton("Delete", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//perform your delete callback here
dialog.dismiss();
}
});
alert.show();
return true;
}
});
Update1: Explanation to Amiya's answer,
The reason why
cursor.moveToFirst() isn't a good option is because this statement
is unnecessary. The compiler knows exact spot to hit when it will
enter inside your DB. One usually perform cursor.moveToFirst()
when you need to iterate through all or some data elements from your
database.
"Make sure, COLUMN_ID is PRIMARY Key." Reason behind this is to avoid duplicity in case you ever add a functionality of adding items on the run time.
REMOVE this if (cursor.moveToFirst()) .
Make sure, COLUMN_ID is PRIMARY Key.
Check deleteHandler() method is invoking or not.
You should try with
public void deleteHandler(String username, String IP)
{
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_USER,
COLUMN_NAME + " = ? AND " + COLUMN_ID + " = ?",
new String[] {username, IP});
db.close();
}
I have a problem. I try to delete the record from the database. I have no idea, but how to do it. I tried something like this, but not quite work.
The basic gist is that I trying to delete from the database based on list item position, not database row ID. How delete base database row ID?
ListView listawszystkich;
public int pozycja;
DatabaseDEO db = new DatabaseDEO(this);
final String[] skad = new String[]{Database.tables.Transakcje.Kolumny.kwota, Database.tables.Transakcje.Kolumny.data, Kategorie.KOLUMNY.nazwa_kategorii, Database.tables.Transakcje.Kolumny.komentarz};
final int[] dokad = new int[]{R.id.kwotaglowna,R.id.dataglowna,R.id.kategoriaglowna,R.id.komentarzglowny};
private SimpleCursorAdapter adapterspinner;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_transakcje2);
listawszystkich = (ListView) findViewById(R.id.listawszystkich);
listawszystkich.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
pozycja = position+1;
}
});
Cursor kursorwszystkie = db.wszystkietransakcje();
adapterspinner = new SimpleCursorAdapter(getApplicationContext(), R.layout.activity_transakcje,kursorwszystkie,skad, dokad,0);
adapterspinner.notifyDataSetChanged();
listawszystkich.setAdapter(adapterspinner);
registerForContextMenu(listawszystkich);
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
if (v.getId()==R.id.listawszystkich) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_list,menu);
}
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
case R.id.delete:
db.usuwanietransakcji(pozycja);
Transakcje.this.recreate();
Toast.makeText(getApplicationContext(), "Delete", Toast.LENGTH_SHORT).show();
default:
return super.onContextItemSelected(item);
}
Method to delete row (in DatabaseDEO):
public void usuwanietransakcji(int id_transakcji){
SQLiteDatabase db = DbHelper.getWritableDatabase();
db.execSQL("DELETE FROM " + Transakcje.NAZWA_TABELI+ " WHERE "+Transakcje.Kolumny.id_transakcji+"='"+id_transakcji+"'");
db.close();
}
Looks like you're trying to delete from the database based on list position rather than row ID:
db.usuwanietransakcji(pozycja);
I'm guessing id_transakcji is a unique value similar to a row ID? First you'll need to declare Cursor kursorwszystkie as a member variable outside of the onCreate method, but still populate it on the same line.
In onContextItemSelected() you'll need to query your cursor again:
case R.id.delete: {
// Move to the selected row
kursorwszystkie.moveToPosition(info.position);
// Get the column ID of id_transakcji
final int col_id = kursorwszystkie.getColumnIndex(Database.tables.Transakcje.Kolumny.id_transakcji);
// Get id_transakcji
final int id_transakcji = kursorwszystkie.getInt(col_id);
// Query the database
db.usuwanietransakcji(id_transakcji);
Transakcje.this.recreate();
Toast.makeText(getApplicationContext(), "Delete", Toast.LENGTH_SHORT).show();
break;
}
Note the addition of {} as I'm declaring a variable inside a switch case. Also add a break; at the end of the case so the code doesn't fall through into the default block. Let me know if that works.
I am building a custom ListView (card style) and would like to have an edit and delete button on the card. In order to invoke the methods on the correct database rows, I need to know which _id (View) the user selected.
Currently, I am using a context menu which is pretty easy
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
position = (int) info.id;
MenuInflater m = getMenuInflater();
m.inflate(R.menu.history_popup_menu, menu);
}
#Override
public boolean onContextItemSelected(final MenuItem item) {
switch(item.getItemId()){
case R.id.delete:
...
in this case, I get the id (position) in the onCreateContextMenu
I am wanting to get rid of the context menu now and just have edit and delete on the card itself.
How do I go about retrieving the _id from the database and assign it to a value to be used in my delete/edit method?
This is my method for creating the list
private void addItemsToList(){
Cursor cursor = db.getAllLogs();
Log.d("history.java", "finished Cursor cursor = db.getAllLogs();");
String[] from = {"_id", "date", "gallons", "pricePerGallon", "odometer", "filledOrNot", "comments", "totalSpent"};
int[] to = {deleteVal, R.id.cardDate, R.id.cardGallons, R.id.cardPrice, R.id.cardOdometer, R.id.cardFilledOrNot, R.id.cardComments, R.id.usd};
adapter = new SimpleCursorAdapter(this, R.layout.history_list_item, cursor, from, to, 0);
String filledOrNotVal = String.valueOf(R.id.cardFilledOrNot);
if (filledOrNotVal == "False"){
Log.d("history", "False");
} else {
Log.d("history", "True");
}
listContent.setAdapter(adapter);
}