I have an application which retrieves data from DB and displays it in a list view. I have a custom adapter for the same. So when I press the "delete" button, a delete button for each row in the list is displayed. If I press that, the particular row gets deleted in the DB and the same should be reflected in the listview also. The problem is, its not reflecting this change, I should close the app and reopen or move into some other activity and get back to see the updated results.
So my question is: where do I call the notifyDataSetChanged() method to get it updated instantly?
Here is my customadapter view:
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
MenuListItems menuListItems = menuList.get(position);
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) c
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.customlist, parent, false);
}
Button ck = (Button) convertView.findViewById(R.id.delbox);
if(i){
ck.setVisibility(View.VISIBLE);}
else{
ck.setVisibility(View.GONE);
}
ck.setTag(menuListItems.getSlno());
ck.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
final Integer Index = Integer.parseInt((String) v.getTag());
final DataHandler enter = new DataHandler(c);
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case DialogInterface.BUTTON_POSITIVE:
//Yes button clicked
enter.open();
enter.delet(Index);
enter.close();
notifyDataSetChanged();
dialog.dismiss();
break;
case DialogInterface.BUTTON_NEGATIVE:
//No button clicked
dialog.dismiss();
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(c);
builder.setMessage("Are you sure you want to Delete?").setPositiveButton("Yes", dialogClickListener)
.setNegativeButton("No", dialogClickListener).show();
}
});
TextView id = (TextView) convertView.findViewById(R.id.tvhide);
id.setText(menuListItems.getSlno());
TextView title = (TextView) convertView.findViewById(R.id.tvtitle);
title.setText(menuListItems.getTitle());
TextView phone = (TextView) convertView.findViewById(R.id.tvpnumber);
phone.setText(menuListItems.getPhone());
// ck.setChecked(menuList.)
notifyDataSetChanged();
return convertView;
}
You need to delete the data from the adapter of the listview via adapter.remove(adapter.getItem(position)); and then call notifyDataSetChanged() on adapter.
You are storing the data that shows your ListView in a List somewhere (which you didn't show in the code your paste. It would be nice to update your question)
Then, when you remove your data from the dialog, you are deleting the real data, but not the one stored in your List, that you adapter uses to show the ListView. So you simply need to remove this data from this List and then call notifyDataSetChanged() and it will work.
A very basic solution to this would be restarting the activity.
In the Delete button click listener, after you delete the record, restart the activity.
Now it will fetch recent data!
Intent myIntent = new Intent(context,MainActivityName.class);
context.startActivity(myIntent);
Related
I made my own dialog box class. This class has a button to delete an item from a listview(which is the main acctivity_main.xml). When I push the delete button the item does not get deleted.
I have seen this topic Android: how to remove an item from a listView and arrayAdapter. It just appears the user does not know how to get the item index correctly, which I believe I have done correctly.
Remove ListView items in Android This one is pretty close. But in my code I created my own dialog, this one is using a positive and negative button. I am passing variables between my dialog class and to the mainActivity.
my onClickListener in OnCreate withing the MainActivity
mFoodDataAdapter = new FoodDataAdapter();
final ListView listFoodData = (ListView) findViewById(R.id.listView);
listFoodData.setAdapter(mFoodDataAdapter);
//Handle clicks on the ListView
listFoodData.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View view, int whichItem, long id) {
FoodData tempFoodData = mFoodDataAdapter.getItem(whichItem);
//create a new dialog window
DialogShowFood dialog = new DialogShowFood();
// send in a reference to the note to be shown
dialog.sendFoodDataSelected(tempFoodData);
FoodDataAdapter adapter1 = new FoodDataAdapter();
/*this is where i send the data to the DialogShowFood.java*/
dialog.sendFoodDataAdapter(adapter1, whichItem);
// show the dialog window with the note in it
dialog.show(getFragmentManager(),"");
}
});
Here is my class for the dialog "DialogShowFood.java"
public class DialogShowFood extends DialogFragment {
FoodData mFood;
MainActivity.FoodDataAdapter mAdapter;
int mitemToDelete;
#Override
public Dialog onCreateDialog(Bundle savedInstanceState){
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View dialogView = inflater.inflate(R.layout.dialog_show_food, null);
Button btnDelete = (Button) dialogView.findViewById(R.id.btnDelete);
builder.setView(dialogView).setMessage("Your food");
/*this sends the item to delete to the adapter*/
btnDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mAdapter.deleteFoodData(mitemToDelete);
dismiss();
}
});
return builder.create();
}
/*this gets the data to delete from the MainActivity*/
public void sendFoodDataAdapter(MainActivity.FoodDataAdapter adapter1, int whichItem) {
mAdapter = adapter1;
mitemToDelete = whichItem;
}
}
The function inside the adapter
/*this is the function in the base adapter to delete the item*/
public void deleteFoodData(int n){
Toast.makeText(MainActivity.this,Integer.toString(n), Toast.LENGTH_SHORT).show();
foodDataList.remove(n);
notifyDataSetChanged();
}
The Toast outputs the proper indexes of the item to delete, it just does not delete the item for some reason.
I made a list view u can delete an item by touch the row of that listview, but it always deleting the last item, and after some delete times it shows index out of bound error
system was when u toch an item a dialogue box open u click print then item will removed the item and open an activity for few seconds.
here is the list adapter class
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final int positionplayer = position;
ViewHolderaway1 holder;
if (convertView == null) {
View row = inflater.inflate(R.layout.readonlyvendorlist, parent,
false);
row.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
// set title
try {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
context);
alertDialogBuilder.setTitle(values.get(positionplayer).Voucherref
+ " Sell");
// set dialog message
alertDialogBuilder
.setMessage(
values.get(positionplayer)
.getVoucherref() + "For Print")
.setCancelable(false)
.setPositiveButton("Print Voucher",
new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface dialog,
int id) {
// if this button is clicked,
// close
PrintTestAcitvity.printettext = values
.get(positionplayer).PrinterText;
ListService.printerlist
.remove(positionplayer);
Datasync.storedataprint(context);
notifyDataSetChanged();
Intent ia = new Intent(context,
PrintTestAcitvity.class);
context.startActivity(ia);
}
})
.setNegativeButton("Cancell",
new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface dialog,
int id) {
// if this button is clicked,
// just close
// the dialog box and do nothing
Toast.makeText(
context,
"Printing Data store for locally",
Toast.LENGTH_LONG)
.show();
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
} catch (IndexOutOfBoundsException e) {
// TODO: handle exception
notifyDataSetChanged();
}
}
});
holder = new ViewHolderaway1();
holder.ProductItemID = (TextView) row
.findViewById(R.id.ProductItemID);
holder.VoucherCost = (TextView) row.findViewById(R.id.VoucherCost);
holder.SupplierID = (TextView) row.findViewById(R.id.SupplierID);
Log.d("goru", "gadha");
row.setTag(holder);
holder = (ViewHolderaway1) row.getTag();
// Printer Productsdata = values.get(positionplayer);
// if (Productsdata != null) {
// holder.ProductItemID.setText("Print");
// holder.VoucherCost.setText(Productsdata.getVoucherref());
// // holder.SupplierID.setText(resid)
// // holder.SupplierID.setVisibility(View.GONE);
//
// if (Productsdata.getVoucherref().contains("Voda")) {
// holder.VoucherCost.setBackgroundColor(Color.RED);
// holder.VoucherCost.setTextColor(Color.WHITE);
// holder.SupplierID.setBackgroundDrawable(getContext()
// .getResources().getDrawable(R.drawable.voda));
// }
// if (Productsdata.getVoucherref().contains("Eco")) {
// holder.VoucherCost.setBackgroundColor(Color.BLUE);
// holder.VoucherCost.setTextColor(Color.WHITE);
// holder.SupplierID.setBackgroundDrawable(getContext()
// .getResources().getDrawable(R.drawable.eco));
// }
//
// }
convertView = row;
}else
{
holder = (ViewHolderaway1) convertView.getTag();
}
Printer Productsdata = values.get(positionplayer);
if (Productsdata != null) {
holder.ProductItemID.setText("Print");
holder.VoucherCost.setText(Productsdata.getVoucherref());
// holder.SupplierID.setText(resid)
// holder.SupplierID.setVisibility(View.GONE);
if (Productsdata.getVoucherref().contains("Voda")) {
holder.VoucherCost.setBackgroundColor(Color.RED);
holder.VoucherCost.setTextColor(Color.WHITE);
holder.SupplierID.setBackgroundDrawable(getContext()
.getResources().getDrawable(R.drawable.voda));
}
if (Productsdata.getVoucherref().contains("Eco")) {
holder.VoucherCost.setBackgroundColor(Color.BLUE);
holder.VoucherCost.setTextColor(Color.WHITE);
holder.SupplierID.setBackgroundDrawable(getContext()
.getResources().getDrawable(R.drawable.eco));
}
}
return convertView;
}
There are some major flaws with your logic in getView(), this is the biggest one:
if (convertView != null)
{
holder = new ViewHolderaway1();
return convertView;
}
This returns the recycled row without altering it... At a minimum you need to change the written content of the layout.
Look at the code in this answer: https://stackoverflow.com/a/4145996/1267661. You should use this as template. It demonstrates how to properly use a ViewHolder and display accurate data after Views are returned from ListView's RecycleBin.
Addition
This new code is much more efficient! Also I think I see why only the last row is deleted. In your AlertDialog you reference positionplayer but this onClick() code is run after getView() has finished, so positionplayer is not helpful here. Since your OnClickListener refers to the whole row, you should use the OnItemClickListener in your Activity instead and this will help delete the appropriate row:
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// Move your AlertDialog code here and use position instead of positionplayer
}
});
My ListViewItems have delete buttons in them. From those button's click events I want to show a confirmation dialog before deleting the item via it's ID from the database. The ID is stored in the item's ViewHolder.
How can I access the item's ViewHolder from the AlertDialog's click handler? Here is the relevant code. Compiler chokes on "V" inside onClick(DialogInterface dialog, int whichButton).
I could store the ID in the button's tag but that feels awkward.
I'm targetting minimum API level 8 but let me know if higher API levels have a solution for this. It's my first Android program so there may very well be an obvious solution.
private static class MyAdapter extends CursorAdapter {
//.....
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = View.inflate(context, R.layout.my_detail, null);
MyViewHolder holder = new MyViewHolder();
holder.deleteButton = (Button) view.findViewById(R.id.deleteButton);
holder.deleteButton.setOnClickListener(deleteButtonClickListener);
holder.editButton = (Button) view.findViewById(R.id.editButton);
holder.editButton.setOnClickListener(editButtonClickListener);
holder.nameTextView = (TextView) view
.findViewById(R.id.nameTextView);
holder.itemId = cursor.getLong(cursor
.getColumnIndex(MyData.ID_COLUMN));
view.setTag(holder);
return view;
} // newView()
//.....
private OnClickListener deleteButtonClickListener = new OnClickListener() {
public void onClick(View v) {
new AlertDialog.Builder(_context)
.setTitle("Delete?")
.setMessage("Delete item?")
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
MyViewHolder holder = (MyViewHolder) ((View) v
.getParent()).getTag();
long itemId = holder.itemId;
_MyData.deleteItem(itemId);
}
}).setNegativeButton(android.R.string.no, null)
.show();
} // onClick()
}; // deleteButtonClickListener
//.....
}
Your code actually looks pretty good, the only change needed is that v needs to be declared final, like so:
private OnClickListener deleteButtonClickListener = new OnClickListener()
{
public void onClick(final View v) { }
}
The reason for this is due to how Java implements closures. v should be final so that our implementation of DialogInterface.OnClickListener in the setPositiveButton() has access to the variable.
first implement the onclickevtn
private static class MyAdapter extends CursorAdapte mplements android.view.View.OnClickListener
then set the event for particular
holder.editButton.setOnClickListener(this);
then override the class function
#Override
public void onClick(View v) {
if(R.id.editButton==v.getId()){
....do something
}else
}
this will work after struggling i got this way
Tag the itemid in delete button so that you can retrieve it in dialogbox
E.g
holder.deleteButton.setTag(cursor.getLong(cursor
.getColumnIndex(MyData.ID_COLUMN)));
And retrieve it in dialogbox
long itemId = v.getTag();
I have created a screen with 5 rows of information. each row has 2 values. (value1 and value2)
At the end of each row is a button. For each row I have created a xml file that I am looping though and filling in the values from a database
what I am looking at doing is when the button is pressed a dialog is opened with two editviews filled in with the values from that row
Then when the button is pressed on the dialog the values are updated in database.
I am having problems with the createdialog / preparedialog methods and passing the values to them.
UPDATE with Code
public void createLayout(LinearLayout pMainlayout, String pMajorValue) {
DatabaseTools db = new DatabaseTools(this);
majorValue= pMajorValue;
nameInfo = db.getNames(pMajorValue);
name = returnName(pMajorValue);
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (int i = 0; i < nameInfo.size(); i++) {
// Get views
View view = (View) inflater.inflate(R.layout.mainlayout, null);
TextView nameView = (TextView) sightmarkView.findViewById(R.id.name_title);
TextView Value1View = (TextView) sightmarkView.findViewById(R.id.value1);
TextView ValueView = (TextView) sightmarkView.findViewById(R.id.value2);
Button updateButton = (Button) sightmarkView.findViewById(R.id.updatebutton);
// Get info from Database
nameValue = nameInfo.get(i).toString();
value1v = db.getMark(majorValue, nameInfo.get(i).toString());
value2v = db.getMark(majorValue, nameInfo.get(i).toString());
// populate info into fields
nameView.setText(nameValue);
Value1View.setText(String.valueOf(value1));
Value2View.setText(String.valueOf(value2));
updateButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Bundle bundle = new Bundle();
//Code here to add values to a bundle
showDialog(SIGHTMARK_DIALOG_ID, bundle);
}
});
pMainlayout.addView(view);
}
}
All this work correctly. The values are displayed. I have looked into using a bundle to pass them into the dialog
#Override
protected Dialog onCreateDialog(int id, Bundle bundle) {
switch(id) {
case DIALOG_ID:
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View layout = inflater.inflate(R.layout.update, (ViewGroup) findViewById(R.id.update));
final EditText value1Edit = (EditText) layout.findViewById(R.id.value1_current);
final EditText value2Edit = (EditText) layout.findViewById(R.id.value2_current);
//next pull values from bundle to populate into fields
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(layout);
// Now configure the AlertDialog
builder.setTitle(R.string.sight_update_title);
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
this.removeDialog(DIALOG_ID);
}
});
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
value1New = Float.parseFloat(value1Edit.getText().toString());
value2New = Float.parseFloat(value2Edit.getText().toString());
// method run to update the database with the new values passed to it
updateMarks(value1, value2);
this.removeDialog(DIALOG_ID);
}
});
// Create the AlertDialog and return it
AlertDialog Dialog = builder.create();
return Dialog;
}
return null;
}
This part has issues and is not getting the values correctly or passing them to the update method
i think the problem is here:
If you use showDialog(int), the activity will call through to this
method the first time, and hang onto it thereafter. Any dialog that is
created by this method will automatically be saved and restored for
you, including whether it is showing.
remove references
removeDialog(SIGHTMARK_DIALOG_ID);
showDialog(SIGHTMARK_DIALOG_ID, bundle);
documentation
I am trying to implement ListView with Delete functionality to delete item from the listview. I am successful to delete but failed to refresh the listview after deletetion of an item from the database.
Actually, Click on listitem, i am displaying AlertBox for "Delete" and "Cancel" action, on clicking "Delete", item should be removed from the database and as well as from the listview and listview should be refreshed. I have also used notifyDataSetChanged() method.
lview = (ListView) findViewById(R.id.lview);
adapter = new ListView_CustomAdapter(this, listitemDisplay);
lview.setAdapter(adapter);
lview.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> a, View v, int position, long id)
{
Show_Alert_box(v.getContext(),"Please select action.",position);
}
});
and the code for Show_Alert_box:
public void Show_Alert_box(Context context, String message,int position)
{
final int pos = position;
final AlertDialog alertDialog = new AlertDialog.Builder(context).create();
alertDialog.setTitle(getString(R.string.app_name_for_alert_Dialog));
alertDialog.setButton("Delete", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
try
{
db.open();
String[] whereArgs={String.valueOf(pkID)};
return db.delete(DATABASE_TABLE_4,"pk_pkID == ?",whereArgs);
adapter.notifyDataSetChanged();
db.close();
}
catch(Exception e)
{
}
} });
alertDialog.setButton2("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
} });
alertDialog.setMessage(message);
alertDialog.show();
}
Does it remove it from your list adapter?
If not that would be the reason the notifyDataSetChanged() won't do you much good.
Actually looking at your code again i can only find that you're removing it from your database and not the adapter itself.
edit (to answer comment):
Well that's hard to do without your ListView_CustomAdapter class.
The problem is, in this adapter there's a data set (the one you put in the constructor (listitemDisplay)) which needs to be updated as well. Only then the notifyDataSetChanged() will work.
Call that Activity once again Using Intent
I'm guessing that using
getActivity().recreate();
instead of restarting the activity via a new Intent is better because using a new Intent will only stop the current activity and not destroy it.
Anyway, it works.
if you have the cursor, call requery() before calling notifyDataChanged()
I did something like this in my adapter:
((Activity)cxt).finish();
Intent intent = new Intent(cxt, YourActivity.class);
cxt.startActivity(intent);
This ends the activity and then starts the same one again.
I think instead of calling the activity again, you should set the adapter to the listview on the alertBox delete option after getting the updated data from the database and putting into listitemDisplay list like this.
alertDialog.setButton("Delete", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
try
{
db.open();
String[] whereArgs={String.valueOf(pkID)};
return db.delete(DATABASE_TABLE_4,"pk_pkID == ?",whereArgs);
listitemDisplay = db.getItemFromDB();
adapter = new ListView_CustomAdapter(this, listitemDisplay);
lview.setAdapter(adapter);
db.close();
}
catch(Exception e)
{
}
} });
This will refresh the listView
I have the solution:
If you want to delete a row from a list view clicking on the DELETE button of each of that row do this. Here you have an example of a custom adapter class with a name and a delete button. Every time you press the button the row is deleted
public class UserCustomAdapter extends ArrayAdapter<User>{
Context context;
int layoutResourceId;
ArrayList<User> data = new ArrayList<User>();
public UserCustomAdapter(Context context, int layoutResourceId,ArrayList<User> data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View row = convertView;
UserHolder holder = null;
if (row == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new UserHolder();
holder.textName = (TextView) row.findViewById(R.id.textView1);
holder.btnDelete = (Button) row.findViewById(R.id.button2);
row.setTag(holder);
} else {
holder = (UserHolder) row.getTag();
}
User user = data.get(position);
holder.btnDelete.setTag(position);
holder.textName.setText(user.getName());
holder.btnDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String pos = v.getTag().toString();
int _posicion = Integer.parseInt(pos);
data.remove(_posicion);
notifyDataSetChanged();
}
});
return row;
}
static class UserHolder {
TextView textName;
Button btnDelete;
}
}
Try calling refreshDrawableState to tell the list to redraw.
Make a new function outside your onCreate block {something like... getdata()} and inside that insert and get all your data and set to the adapter.
Then call the function again in your onResume() block. So whenever you will delete the data from the list it will reflect immediately.