I show dialog of checkboxes (list retrieved from DB) to allow user select, which rows remove. Because android dialog caching, I need to refresh count and names of checkboxes.
In my onCreateDialog:
dialog = new AlertDialog.Builder( this )
.setTitle( "Remove Items" )
.setMultiChoiceItems( items, _selections, new OnMultiChoiceClickListener(){public void onClick (DialogInterface dialog, int which, boolean isChecked){}} )
.setPositiveButton("Smazat", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
deleteRow(_selections);
} })
.setNegativeButton("Storno", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
} })
.create();
How refresh values (items,_selections) in onPrepareDialog?
I tried invalidate views, hoping that force android to load items againg(dont work neither), but I think its bad choice as well as removing dialog and recreating.
protected void onPrepareDialog(final int id, final Dialog dialog) {
switch (id) {
case REMOVE_DIALOG_ID:
ListView lv = ((AlertDialog) dialog).getListView();
lv.invalidateViews();
break;
}
Thanks for any ideas!
When you create a list of items using AlertDialog.Builder, it internally takes that and creates a ListAdapater that is dependent on the type of data you passed. Since "items" in your example doesn't look like a resource ID, I'm assuming it's either a CharSequence[] or a Cursor. If you provide more information about what "items" is, I can provide a more concrete example.
For CharSequence[] (like String[]) data, Builder creates an ArrayAdapter instance.
For Cursor data, Builder creates a CursorAdapter
You will need to obtain a reference to this ListAdapter using getListView().getAdapter() on the AlertDialog instance.
For a Cursor, you can get away with calling notifyDataSetChanged() after you have called requery() to update the data set.
Since you can't "update" an array with new data (changing the pointer to a new instance is not the same thing...the instance that the adapter is pointing to stays unchanged), this case is a little more work. You will need to call the add(), clear(), etc. methods of the adapter to remove invalid items and add the updates ones. With the adapters data set fully updated, you may now call notifyDataSetChanged().
Hope that Helps!
I spent lot of time to search for same solution and eventually fixed my problem with simple stuff after trying to use onPrepareDialog too
I use the removeDialog(int) function of the Activity. When a dialog is dismissed, the Activity basically stores the state of the dialog (for performance reasons I would imagine). Calling removeDialog(int) on the dialog forces the activity to unload all references for the dialog and dismisses it from the screen if it's being shown.
did this when my activity lost focus simply add:
public void onStop() {
removeDialog(Id_Dial);
return;
}
My technique is to create an adapter with empty data in onCreateDialog and completely replace the adapter during onPreparDialog.
Example:
#Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DialogMergeRegion:
title = ...
return new AlertDialog.Builder(BaseDataTabView.this)
.setTitle(title)
.setMultiChoiceItems(new CharSequence[0], null,
new OnMultiChoiceClickListener() {
#Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
manageSelectionList(which, isChecked);
}
})
//...
.create();
}
}
#Override
protected void onPrepareDialog(int id, Dialog dialog) {
super.onPrepareDialog(id, dialog);
switch (id) {
case DialogMergeRegion: {
List<String> regionNames = ...// get the data
ListAdapter mergeAdapter = new ArrayAdapter<String>(this, android.R.layout.select_dialog_multichoice, regionNames);
AlertDialog ad = (AlertDialog) dialog;
ad.getListView().setAdapter(mergeAdapter);
break;
}
}
In your onPrepareDialog method, instead of using invalidateViews(), you should try getting the adapter of the ListView and try calling either notifyDataSetChanged() or notifyDataSetInvalidated(). Does that help?
Related
So I have an ArrayList of a custom object and an adapter to show the contents through a ListView. You can click on separate objects in the ListView and a little animation expands and shows some extra informations. This behaviour is defined in the ArrayAdapter (because the animations didn't work how I wanted it to when used directly in createView().
Now if you click on a small image (X- to delete) of a listview element, an alertdialog pops up asking you if you're sure you want to delete that item. If you click Yes it removes it from the arraylist but notifyDataSetChanged(); doesn't refresh the adapter and onResume or something similar is never called because I never hid the fragment, just had an alert over it.
this is a rough code, part of my ArrayAdapter:
deleteIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
...
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
ArrayList<Book> XYZ = sharedFunctions.loadSortedArrayList(getContext());
XYZ.remove(position);
sharedFunctions.saveArrayList(context, XYZ);
notifyDataSetChanged();
break;
case DialogInterface.BUTTON_NEGATIVE:
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage("BLABLA").setNegativeButton("Cancel", dialogClickListener).setPositiveButton("Confirm", dialogClickListener).show();
}
});
So how can I tell the Fragment (which is a tab) that the data has changed?
EDIT:
So I think the answers below were technically correct but I figured out that I was simply doing this all wrong. I removed the item from the ArrayList (which was loaded/saved in SharedPreferences) instead of removing it from the ArrayList that was used to construct the adapter. Stupid mistake tbh. Once I removed it from there as well, notifyDataSetChanged() worked. Thanks to you both for trying to help.-- (pretty new here so I'm not sure if i should delete the question but I'll just keep it like this for now).
You have to access your fragment through the fragment manager. Here is an example how to do so:
ExampleFragment fragment = (ExampleFragment) getChildFragmentManager().findFragmentByTag("theTagThatFragmentSavedInFragmentManagerWith");
if (fragment != null) fragment.notifyItemChanged(itemPosition);
For this you can also use localbroadcastreciever too. define and register local braodcast in that fragment which you want to refresh and call that broadcast from adapter delete positive click. in broadcast onRecieve just check your adapter is not null and do like this
youradapterobject.notifyDataSetChanged();
So right now I have a custom listview adapter that adds another row when the user selects a item. The thing is, each item in the row should have a modification button where they can choose to add whatever modification it is (can choose more than one modification)
This is a food ordering app that when the item is selected, there should be another button in the list labeled "Modify", where a pop-up comes up and allows the user to choose what modification it wants by using checkbox. ("Less salt", "More sauce", etc). Each modification list is the same for each dish. When the user exits the popup and clicks on the same modify button, the checkboxes checked should stay there.
I originally created a Popup class where when the button is selected, there is an intent to jump to that Popup activity, but I couldn't find the relationship between the custom adapter and the Popup activity. I also tried using an AlertDialog to replace the Popup window, but could not find a way to save all the checked items and show which ones were selected before.
Here's my code
modifyBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Modification");
final CharSequence[] modify_items = orderClass.getModifyList()
.toArray(new CharSequence[orderClass.getModifyList().size()]);
builder.setMultiChoiceItems(modify_items, null, new DialogInterface.OnMultiChoiceClickListener() {
#Override
public void onClick(DialogInterface dialog, int indexSelected, boolean isChecked) {
if(isChecked){
selectedList.add(indexSelected);
selectedItems.set(position, selectedList);
}
else if(selectedList.contains(indexSelected)){
selectedList.remove(Integer.valueOf(indexSelected));
selectedItems.set(position, selectedList);
}
}
})
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
AlertDialog dialog = builder.create();
dialog.show();
Log.d("dialog", "Showing dialog");
}
});
return view;
}
You need to put data in a holder structure(its kinda a class that holds variables)
then you can show data by index and theres is a relation between the list view index shown and the data index so when is a list view cell clicked you get the position then find it in the structure and post it to another activity or anything else to modify it remember you have to declare a flag to launch the activity else the app will crash i think its called activtyoutofbound index or something like this
I'm working on an android app and my requirement is that, I need to display the cursor values into alertdialog and let the user choose an item from the list and the value selected should be returned to the calling Activity.In my app, based on the student info, the cursor holds the values of courses he is taking. So the user should be able to choose one of the courses and then that value should be returned to the Activity that called alertdialog. Can you please let me know how to proceed on this.I've looked at multiple examples and none seems to work exactly.
Here is my sample code
final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
final Cursor courses=dbConnector.getCourses(student);
builder.setTitle("Enter Course");
builder.setCursor(courses, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int itemSelected) {
if (courses.moveToPosition(itemSelected)) {
String text=courses.getString(0);
Toast.makeText(getApplicationContext(),
"You selected: "+text,
Toast.LENGTH_SHORT);
builder.show();
}
courses.moveToFirst();
}
},"course");
builder.create();
createRow(sview, student, pass,text);
Now I want to return the text variable to the Calling Activity but, here it is local to the onClick() method. How can we do that without having to extend any DialogFragment class.
I suggest you calling a method of the class inside overridden onClick method and do whatever you like with that because the method will be in the Activity like here
#Override
public void onClick(DialogInterface dialogInterface, int itemSelected) {
myMethod(itemSelected);
}
private void myMethod(int selectedItem){
//Do whatever with that selected item
}
Could someone point out a working example of a custom dialog that takes an ArrayAdapter as input and shows a selectable list.
I have tried to create a Dialog using an AlertDialog Builder as such...
final ArrayAdapter<MyObject> myAdapter = getMyobjects();
final AlertDialog.Builder builder = new AlertDialog.Builder(this).setTitle("Pick an item").setAdapter(myAdapter,
new android.content.DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int item) {
Toast.makeText(Islands.this, myAdapter.getItem(item).toString(), Toast.LENGTH_SHORT).show();
}
});
final AlertDialog alert = builder.create();
return alert;
My problem is that my dialog is not updating then i called
#Override
protected void onPrepareDialog(final int id, final Dialog dialog) {
switch (id) {
case DIALOG_GET_AVAIL_DESTS:
((AlertDialog) dialog).getListView().setAdapter( getDestinations());
break;
}
}
However the onClick listener listens to the initial set of items...
Indeed AlertDialog is implements Facade design pattern with this class behind :
http://www.netmite.com/android/mydroid/frameworks/base/core/java/com/android/internal/app/AlertController.java
And the whole code is such a mess...
I took 3 hours to try to do that, and I am going to build a dialog from scratch, using android.R.layout as a basis.
Steff
You have to make a call to
invalidateViews()
on your listview - that will cause it to redraw the view with the updates.
Since you are using onPrepareDialog(int id, Dialog dialog), I am guessing you're initially setting up the dialog in onCreateDialog(int id).
Doing so cause the system to save the dialog you initially create. In order to achieve the desired functionality, when the dialog is dismissed, tell the system to discard it by calling android.app.Activity.removeDialog(int id).
Any subsequent invocations will have your dialog regenerated through the onCreateDialog(int id) method, causing the set of items to be updated.
I'm using and ArrayAdapter to populate a ListView. After selecting and item, it displays a confirmation Y/N dialog. If the user's choice is negative, then he should be able to select another item showing the same dialog. And so on.
Here's my code:
lView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(final AdapterView<?> parent, final View v, final int index, final long id) {
Toast.makeText("Selected file"+ mFiles.get(index).getfileName(),
Toast.LENGTH_SHORT).show();
SelectedFile = mFiles.get(index);
showDialog(DIALOG_CONFIRMIMPORT_ID);
}
});
The weird thing is that while the "Toast" shows the clicked item every time, only the first selected item since the Activity is initiated is being passed to "SelectedFile". No matter how many times you click a diferent item, "SelectedFile" always assumes the same value, the value of the first clicked item, outside of this code.
Heres's my Dialog code:
Protected Dialog onCreateDialog(int id) {
switch(id) {
case DIALOG_CONFIRMIMPORT_ID:
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
String message = String.format(getString(R.string.importstudentfileconfirm),SelectedFile.getfileName());
builder.setMessage(message)
.setCancelable(false)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Activity.this.finish();
// startActivity(new Intent(Activity.this, LOL.class));
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
SelectedFile = null;
dismissDialog(DIALOG_CONFIRMIMPORT_ID);
mFiles.notifyAll();
}
});
AlertDialog alert = builder.create();
return alert;
}
}
return null;
}
Thank you very much for any help!
I'm guessing this has something to do with the fact that the onCreateDialog method is only called the first time the dialog is created. So the first time you see the dialog it will have the correct filename.
After onCreateDialog is called, onPrepareDialog(...) is called. onPrepareDialog, allows you to change the dialog after it has been created, but before it gets displayed.
Remember that underneath everything, Android isn't creating a new Dialog for you every time you want to show the DIALOG_CONFIRMIMPORT_ID dialog. It is too computationally expensive to instantiate a new dialog every time. Instead, it creates it once, which causes onCreatDialog to be called, followed by the onPrepareDialog. Every other time the dialog is shown, it only calls onPrepareDialog.
Check out the following article on the Android Developer site. It explains things pretty clearly.
http://developer.android.com/guide/topics/ui/dialogs.html#ShowingADialog
So try using onCreateDialog just for initialization of stuff that won't change between showings of the dialog, then use the onPrepareDialog method to dynamically update the contents of the dialog (i.e. getting the new filename)
Cheers!