Android AlertDialog with dynamically changing text

2019-03-09 13:32发布

问题:

I want to show an AlertDialog with one option that might change on every request. So for example at one time I want to show the option "add to contacts" while another time it should be "remove from contacts".

My code does work on the first time, however Android seems to cache the AlertDialog so that onCreateDialog is not executed next time. Therefore the option doesnt change anymore. Can I prevent this caching, or is there just another way of changing the option?

I am working with SDK 1.5 but using 1.1.

@Override
protected Dialog onCreateDialog(final int id) {
    ...
    String add_remove_contact = res.getString(R.string.profile_add_to_contacts);
    if (user.getContacts().contains(profileID)) {
        add_remove_contact = res.getString(R.string.profile_remove_from_contacts);
        // TODO: this string is not changed when contact status changes 
    }
    final CharSequence[] items = {res.getString(R.string.view_profile),
                                  res.getString(R.string.profile_send_message),
                                  add_remove_contact};
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    ...
    return builder.create();
}

回答1:

You can also 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.

Creating Dialogs
Activity#removeDialog(int)



回答2:

Take a look at onPrepareDialog method that will be called before dialog is shown. There You can change the required values based on request type.

Example with date picker

@Override
protected Dialog onCreateDialog(final int id) {
  switch (id) {
  case DIALOG_DATE_ID:
    final Calendar c = Calendar.getInstance();
    return new DatePickerDialog(this, this, c.get(Calendar.YEAR),
                                c.get(Calendar.MONTH), 
                                c.get(Calendar.DAY_OF_MONTH));
  default:
    return super.onCreateDialog(id);
  }
}

@Override
protected void onPrepareDialog(final int id, final Dialog dialog) {
  switch (id) {
  case DIALOG_DATE_ID:
    //update to current time
    final Calendar c = Calendar.getInstance();
    ((DatePickerDialog) dialog).updateDate(c.get(Calendar.YEAR), 
                                           c.get(Calendar.MONTH), 
                                           c.get(Calendar.DAY_OF_MONTH));
    break;
  }
}


回答3:

This is a dup of this question: Android: Can not change the text appears in AlertDialog

You can also do it this way: http://andmobidev.blogspot.com/2010/03/modifying-alert-dialogs-list-items.html

Does seem to slow down the display of the longpress menu though...



回答4:

I think I have a fix for the inconsistent behavior mentioned above. When initially creating the dialog (when it's still an AlertDialog.Builder), you have to set the message to an initial state (not null) or onPrepareDialog will NOT overwrite it with the intended value. So when you're creating the dialog, do something like this to always have a non-null value in the message. I struggled with this for days and found this solution by accident:

AlertDialog.Builder resultAlert = new AlertDialog.Builder(context);

if ( message == null ) {
    resultAlert.setMessage("");
} else {
    resultAlert.setMessage(message);
}


回答5:

I understand the performance reasons for using activity managed dialogs, but would recommend that they are not used except for simple cases. The reasons for this are:

  1. The Bundle argument was only added in API Level 8, so can't be adopted for backwards compatibility. This effectively means that 'onPrepareDialog' needs to rely on non-local variables for state differences;

  2. Practice indicates poor and inconsistent behaviour in response to any dialog changes made in the body of 'onPrepareDialog'.

None of these difficulties arise if Dialogs are subclassed and created as needed. 'setOwnerActivity' can be called if necessary.



回答6:

When you have a custom dialog you can change custom items by using dialog.getWindow().findViewById(...)

This example save the last text shown and display it again the next time you show the dialog.

// custom dialog
final Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.customized);

dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
    @Override
    public void onDismiss(DialogInterface dialogInterface) {
       EditText dialogText = (EditText)dialog.getWindow().findViewById(R.id.customText);
       savedText = dialogText.getText();
    }
});

dialog.show();
EditText dialogText = (EditText)dialog.getWindow().findViewById(R.id.customText);
dialogText.setText(savedText);

Customized dialog's xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

<Button
    android:id="@+id/buttonOK"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="OK"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_marginBottom="16dp" />

<EditText
    android:id="@+id/customText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="19dp"
    android:hint="Message"
    android:ems="10"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true" />



回答7:

And I got a idea but not so good.*This is used when the users don't use the dialog quite frequently!*The solution :first,you should declare a variable (int type) and make the default value as 0.such as private int i=0; and before you use the showDialog methods of Activity,increase the int variable i and post the value i as the parameter as showDialog method. the code may like this

private int i=0;

//before you show the dialog
this.i++;
this.showDialog(this.i);


回答8:

exactly. for AlertDialog, that was created w/ Builder.create(), onPrepareDialog() is useless. Builder is one-way in that once the dialog is created, you can't update. i mean can't loosely, i am sure you could get a handle to the view and do it all manually, but that defeats the point of using the builder in the first place.

the only solution i found was to manually create / show / dismiss the dialog instead of using onCreateDialog(), showDialog(), etc. i tried calling removeDialog(), but that did not seem to work.