I have a dialog with EditText
for input. When I click the "yes" button on dialog, it will validate the input and then close the dialog. However, if the input is wrong, I want to remain in the same dialog. Every time no matter what the input is, the dialog should be automatically closed when I click on the "no" button. How can I disable this? By the way, I have used PositiveButton and NegativeButton for the button on dialog.

- 484,302
- 314
- 1,365
- 1,393

- 8,259
- 3
- 16
- 9
21 Answers
EDIT: This only works on API 8+ as noted by some of the comments.
This is a late answer, but you can add an onShowListener to the AlertDialog where you can then override the onClickListener of the button.
final AlertDialog dialog = new AlertDialog.Builder(context)
.setView(v)
.setTitle(R.string.my_title)
.setPositiveButton(android.R.string.ok, null) //Set to null. We override the onclick
.setNegativeButton(android.R.string.cancel, null)
.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialogInterface) {
Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// TODO Do something
//Dismiss once everything is OK.
dialog.dismiss();
}
});
}
});
dialog.show();

- 43,104
- 15
- 109
- 137

- 10,849
- 1
- 17
- 11
-
7Hey, better late than never, I was looking for exactly that, thanks, +1 :) This is an elegant way of adding validation to your dialog, especially when you already have a helper wrapping class to deal with alerts – Guillaume Nov 18 '11 at 23:19
-
12Doesnt work. AlertDialog.Builder.setOnShowListener dont exist. http://developer.android.com/reference/android/app/AlertDialog.Builder.html – Leandros Mar 04 '12 at 16:33
-
4With API pre 8, you can call d.getButton(AlertDialog.BUTTON_POSITIVE); as it's public method, but you have to call it show(); has been issued, otherwise zou just get null from it – Hurda Apr 04 '12 at 13:28
-
13You can make this even a tad cleaner by setting a null OnClickListener to the dialog builder (saves the empty "//this will be overridden" listener). – Steve Haley Aug 06 '12 at 11:14
-
1Works also fine with DialogFragments when the AlertDialog is created in the onCreateDialog(Bundle savedInstanceState) method. – Christian Lischnig Aug 20 '12 at 13:15
-
@Leandros you should be looking at [this](http://developer.android.com/reference/android/app/AlertDialog.html) and as mentioned in Bostone comment, you should set the min sdk version to 8+ – Ahmad Y. Saleh Jan 23 '13 at 16:56
-
Hello @Tom I just try your way to prevent dialog from closing but I got some errors, would you like to see my question? http://stackoverflow.com/questions/15488840/eclipse-detect-error-on-the-implementation-of-setonshowlistener – Raditya Kurnianto Mar 18 '13 at 23:27
-
i just put your code @Tom Bollwitt to my app but the dialog wont show. the dialog show went i change `.create();` to `.show();` i really need help @all. this is my question [question](http://stackoverflow.com/questions/15639277/how-dialog-keep-stay-or-disable-dismiss-when-data-is-invalid) – Puja Surya Mar 26 '13 at 17:04
-
fixed. the dialog wont show because i running method without showDialog() and onCreateDialog(). thanks – Puja Surya Apr 29 '13 at 07:50
-
I am getting error here, how to show dialog after above code? d.show() gives error – Dharmik Apr 30 '13 at 10:07
-
@Steve Haley - Agreed, updated the code to set the initial listener to null – Tom Bollwitt Sep 06 '13 at 21:42
-
@Bostone - Great point, updated my answer to note the API compatibility – Tom Bollwitt Sep 06 '13 at 21:42
-
1Work's perfect, Thanks! It's a real shame we need to do this workaround by the default action is to dismiss dialog without check... Bad Google, very bad, what we need then dialog.dismiss() :S – Sulfkain Mar 28 '14 at 10:58
-
Is there any way to prevent closing a `ProgressDialog` when a button is clicked on it? – Joshua Pinter Jul 19 '14 at 17:25
-
mine is not working at first, but after I do make sure d.show() is not before d.setOnShowListener(...) everything is working well. – Yakob Ubaidi Dec 08 '15 at 14:11
-
Not working for me. Either the alert dialog does not show or it gets shown twice when I write d.show() before d.setOnShowListener() and both the dialogs close on Ok click – user4057066 Dec 01 '16 at 05:13
-
dialog should be final and you forgot to call show() – Mehvish Ali Dec 15 '16 at 22:32
-
2@Leandros [setOnShowListener](https://developer.android.com/reference/android/app/Dialog.html#setOnCancelListener) is a `Dialog` method not `Dialog.Builder` or maybe you are referring to old documantation – Peter Chaula Jan 16 '17 at 19:53
-
2**Not preventing dialog from close** with AlertDialog Android API Level 26 – Avinash Kumar Mar 14 '18 at 10:14
-
@AvinashKumar Works for me, compiling with and targeting API 27. – Kevin Krumwiede Aug 26 '18 at 21:21
Here are some solutions for all types of dialogs including a solution for AlertDialog.Builder that will work on all API levels (works below API 8, which the other answer here does not). There are solutions for AlertDialogs using AlertDialog.Builder, DialogFragment, and DialogPreference.
Below are the code examples showing how to override the default common button handler and prevent the dialog from closing for these different forms of dialogs. All the examples show how to prevent the positive button from closing the dialog.
Note: A description of how the dialog closing works under the hood for the base android classes and why the following approaches are chosen follows after the examples, for those who want more details
AlertDialog.Builder - Change default button handler immediately after show()
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Test for preventing dialog close");
builder.setPositiveButton("Test",
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
//Do nothing here because we override this button later to change the close behaviour.
//However, we still need this because on older versions of Android unless we
//pass a handler the button doesn't get instantiated
}
});
final AlertDialog dialog = builder.create();
dialog.show();
//Overriding the handler immediately after show is probably a better approach than OnShowListener as described below
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Boolean wantToCloseDialog = false;
//Do stuff, possibly set wantToCloseDialog to true then...
if(wantToCloseDialog)
dialog.dismiss();
//else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
}
});
DialogFragment - override onResume()
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Test for preventing dialog close");
builder.setPositiveButton("Test",
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
//Do nothing here because we override this button later to change the close behaviour.
//However, we still need this because on older versions of Android unless we
//pass a handler the button doesn't get instantiated
}
});
return builder.create();
}
//onStart() is where dialog.show() is actually called on
//the underlying dialog, so we have to do it there or
//later in the lifecycle.
//Doing it in onResume() makes sure that even if there is a config change
//environment that skips onStart then the dialog will still be functioning
//properly after a rotation.
@Override
public void onResume()
{
super.onResume();
final AlertDialog d = (AlertDialog)getDialog();
if(d != null)
{
Button positiveButton = (Button) d.getButton(Dialog.BUTTON_POSITIVE);
positiveButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Boolean wantToCloseDialog = false;
//Do stuff, possibly set wantToCloseDialog to true then...
if(wantToCloseDialog)
d.dismiss();
//else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
}
});
}
}
DialogPreference - override showDialog()
@Override
protected void onPrepareDialogBuilder(Builder builder)
{
super.onPrepareDialogBuilder(builder);
builder.setPositiveButton("Test", this); //Set the button here so it gets created
}
@Override
protected void showDialog(Bundle state)
{
super.showDialog(state); //Call show on default first so we can override the handlers
final AlertDialog d = (AlertDialog) getDialog();
d.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Boolean wantToCloseDialog = false;
//Do stuff, possibly set wantToCloseDialog to true then...
if(wantToCloseDialog)
d.dismiss();
//else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
}
});
}
Explanation of approaches:
Looking through Android source code the AlertDialog default implementation works by registering a common button handler to all the actual buttons in OnCreate(). When a button is clicked the common button handler forwards the click event to whatever handler you passed in setButton() then calls dismisses the dialog.
If you wish to prevent a dialog box from closing when one of these buttons is pressed you must replace the common button handler for the actual view of the button. Because it is assigned in OnCreate(), you must replace it after the default OnCreate() implementation is called. OnCreate is called in the process of the show() method. You could create a custom Dialog class and override OnCreate() to call the super.OnCreate() then override the button handlers, but if you make a custom dialog you don't get the Builder for free, in which case what is the point?
So, in using a dialog the way it is designed but with controlling when it is dismissed, one approach is to call dialog.Show() first, then obtain a reference to the button using dialog.getButton() to override the click handler. Another approach is to use setOnShowListener() and implement finding the button view and replacing the handler in the OnShowListener. The functional difference between the two is 'almost' nill, depending on what thread originally creates the dialog instance. Looking through the source code, the onShowListener gets called by a message posted to a handler running on the thread that created that dialog. So, since your OnShowListener is called by a message posted on the message queue it is technically possible that calling your listener is delayed some time after show completes.
Therefore, I believe the safest approach is the first: to call show.Dialog(), then immediately in the same execution path replace the button handlers. Since your code that calls show() will be operating on the main GUI thread, it means whatever code you follow show() with will be executed before any other code on that thread, whereas the timing of the OnShowListener method is at the mercy of the message queue.
-
15This is by far the easiest implementation and works perfectly. I've used **AlertDialog.Builder - Change default button handler immediately after show()** and it's working like charm. – Reinherd May 10 '13 at 13:04
-
1@sogger dude, I totally boldly edited your amazing answer because in section 1 you had dismiss(); instead of I believe dialog.dismiss(); thanks so much for the awesome answer! – Fattie May 23 '14 at 11:29
-
Is there any way to prevent closing a `ProgressDialog` when a button is clicked on it? – Joshua Pinter Jul 19 '14 at 17:25
-
@JoshPinter If you have a button in your ProgressDialog, that means you put it in yourself, so you should be able to edit the button logic directly. If you are talking about the back button or clicking off the dialog, you can control that using the setCancellable() methods I think. – Sogger Jul 28 '14 at 18:05
-
Thanks for the reply, @Sogger. Indeed, you have to put the button in yourself with `setButton()` but it will always get dismissed, regardless of the `onClick` methods you use. The only way to prevent it from being dismissed is by showing the dialog, accessing the button and setting the `onClickListener()` via the View. – Joshua Pinter Jul 29 '14 at 01:46
-
On closer inspection, you're absolutely correct. Your approach works great for ProgressDialog as well. Thanks! – Joshua Pinter Jul 29 '14 at 01:47
-
Thanks to @wrapperapps for pointing out the fragment and preference AlertDialog d variables had an error and weren't compiling. Those errors are now fixed. (@wrapperapps don't know why your edit got rejected, but I saw it in my notifications anyway, thanks!) – Sogger May 20 '15 at 23:32
-
-
@Dalvik VM It is to help the code be more readable, and makes possible giving the instruction "//Do stuff, possibly set wantToCloseDialog to true then..." – Sogger Jul 06 '15 at 15:48
-
In the second option with overriding onStart() method you check "d" variable for not being null, why you need to do that? Is there a case when getDialog() might return null? – Oleksandr Berdnikov Apr 08 '16 at 23:45
-
I don't know actually. Since it is in onStart() the dialog should be created and getDialog shouldn't return null, so I don't remember why I put that there. You could probably leave it out. – Sogger Apr 15 '16 at 17:30
-
3holy cow, the more I know about Android the more I feel disgusted... all this just to get a simple dialog working properly. it takes hours just to figure out how to display a dialog – SpaceMonkey May 29 '16 at 13:25
-
In regards to this part: `//Do nothing here because we override this button later to change the close behaviour. //However, we still need this because on older versions of Android unless we //pass a handler the button doesn't get instantiated` What versions specifically require that? If we're not targeting the older versions that require that, I'd rather not add more clutter to my code for every button I need to alter. – InsanityOnABun Sep 09 '16 at 19:01
-
Or you can keep an extra blank line in your code and be backwards compatible, your choice. :P I don't remember which specific versions had the problem, sorry, you would have to go dig through AOSP probably. – Sogger Sep 14 '16 at 16:44
-
@Sogger Help Needed! The above approach fails if the device is rotated while the dialog/fragment present on screen. – harsh_v Jan 13 '17 at 12:25
-
@Sogger Fixed! Instead of setting `OnClickListener` in `onShow`, set this in `onResume` method of the fragment to work across orientation changes, as mentioned in http://stackoverflow.com/a/10661281/3600738 this thread. – harsh_v Jan 13 '17 at 12:33
-
1@harsh_v updated the answer to use onResume() for the next person, thanks! – Sogger Mar 17 '17 at 16:33
-
For **TimePickerDialog** throws _ClassCastException_. So, in onResume() you should cast dialog to _TimePickerDialog_ (not to _AlertDialog_ like in answer). So it should be `final TimePickerDialog d = (TimePickerDialog)getDialog();` – Daniel Oct 05 '17 at 16:33
-
DialogPreference in AndroidX no longer has showDialog(). Instead you should update the dialog in DialogFragment.onStart(). Side note, I don't see why onResume() should be overridden instead of onStart(). Works fine when overriding in onStart() – Mark Apr 02 '19 at 12:41
-
I had left a note in the fragment section to answer that: Doing it in onResume() makes sure that even if there is a config change environment that skips onStart then the dialog will still be functioning properly after a rotation. – Sogger May 21 '19 at 17:47
-
An alternate solution
I would like to present an alternate answer from a UX perspective.
Why would you want to prevent a dialog from closing when a button is clicked? Presumably it is because you have a custom dialog in which the user hasn't made a choice or hasn't completely filled everything out yet. And if they are not finished, then you shouldn't allow them to click the positive button at all. Just disable it until everything is ready.
The other answers here give lots of tricks for overriding the positive button click. If that were important to do, wouldn't Android have made a convenient method to do it? They didn't.
Instead, the Dialogs design guide shows an example of such a situation. The OK button is disabled until the user makes a choice. No overriding tricks are necessary at all. It is obvious to the user that something still needs to be done before going on.
How to disable the positive button
See the Android documentation for creating a custom dialog layout. It recommends that you place your AlertDialog
inside a DialogFragment
. Then all you need to do is set listeners on the layout elements to know when to enable or disable the positive button.
- If you custom dialog has radio buttons, then use RadioGroup.OnCheckedChangeListener.
- If your custom dialog has check boxes, then use CompoundButton.OnCheckedChangeListener.
- If your custom dialog has an
EditText
, then use TextWatcher.
The positive button can be disabled like this:
AlertDialog dialog = (AlertDialog) getDialog();
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
Here is an entire working DialogFragment
with a disabled positive button such as might be used in the image above.
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
public class MyDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// inflate the custom dialog layout
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.my_dialog_layout, null);
// add a listener to the radio buttons
RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.radio_group);
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
// enable the positive button after a choice has been made
AlertDialog dialog = (AlertDialog) getDialog();
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
}
});
// build the alert dialog
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(view)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
// TODO: use an interface to pass the user choice back to the activity
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
MyDialogFragment.this.getDialog().cancel();
}
});
return builder.create();
}
@Override
public void onResume() {
super.onResume();
// disable positive button by default
AlertDialog dialog = (AlertDialog) getDialog();
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
}
}
The custom dialog can be run from an activity like this:
MyDialogFragment dialog = new MyDialogFragment();
dialog.show(getFragmentManager(), "MyTag");
Notes
- For the sake of brevity, I omitted the communication interface to pass the user choice info back to the activity. The documentation shows how this is done, though.
The button is still
null
inonCreateDialog
so I disabled it inonResume
. This has the undesireable effect of disabling the it again if the user switches to another app and then comes back without dismissing the dialog. This could be solved by also unselecting any user choices or by calling aRunnable
fromonCreateDialog
to disable the button on the next run loop.view.post(new Runnable() { @Override public void run() { AlertDialog dialog = (AlertDialog) getDialog(); dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); } });
Related

- 484,302
- 314
- 1,365
- 1,393
-
1This is fine for very simple dialogs, but if the input validation is more complex than what you've shown, or if it contains multiple fields, you need a way to tell the user WHY they can't proceed. – mhsmith Jul 16 '21 at 14:50
-
@mhsmith, true, though for something complex with multiple fields I probably wouldn't use a popup dialog. – Suragch Jul 17 '21 at 03:30
I've written a simple class (an AlertDialogBuilder) that you can use to disable the auto-dismiss feature when pressing the dialog's buttons.
It is compatible also with Android 1.6, so it doesn't make use of the OnShowListener (which is available only API >= 8).
So, instead of using AlertDialog.Builder you can use this CustomAlertDialogBuilder. The most important part is that you should not call create(), but only the show() method. I've added methods like setCanceledOnTouchOutside() and setOnDismissListener so that you can still set them directly on the builder.
I tested it on Android 1.6, 2.x, 3.x and 4.x so it should work pretty well. If you find some problems please comment here.
package com.droidahead.lib.utils;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.View;
import android.view.View.OnClickListener;
public class CustomAlertDialogBuilder extends AlertDialog.Builder {
/**
* Click listeners
*/
private DialogInterface.OnClickListener mPositiveButtonListener = null;
private DialogInterface.OnClickListener mNegativeButtonListener = null;
private DialogInterface.OnClickListener mNeutralButtonListener = null;
/**
* Buttons text
*/
private CharSequence mPositiveButtonText = null;
private CharSequence mNegativeButtonText = null;
private CharSequence mNeutralButtonText = null;
private DialogInterface.OnDismissListener mOnDismissListener = null;
private Boolean mCancelOnTouchOutside = null;
public CustomAlertDialogBuilder(Context context) {
super(context);
}
public CustomAlertDialogBuilder setOnDismissListener (DialogInterface.OnDismissListener listener) {
mOnDismissListener = listener;
return this;
}
@Override
public CustomAlertDialogBuilder setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) {
mNegativeButtonListener = listener;
mNegativeButtonText = text;
return this;
}
@Override
public CustomAlertDialogBuilder setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) {
mNeutralButtonListener = listener;
mNeutralButtonText = text;
return this;
}
@Override
public CustomAlertDialogBuilder setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) {
mPositiveButtonListener = listener;
mPositiveButtonText = text;
return this;
}
@Override
public CustomAlertDialogBuilder setNegativeButton(int textId, DialogInterface.OnClickListener listener) {
setNegativeButton(getContext().getString(textId), listener);
return this;
}
@Override
public CustomAlertDialogBuilder setNeutralButton(int textId, DialogInterface.OnClickListener listener) {
setNeutralButton(getContext().getString(textId), listener);
return this;
}
@Override
public CustomAlertDialogBuilder setPositiveButton(int textId, DialogInterface.OnClickListener listener) {
setPositiveButton(getContext().getString(textId), listener);
return this;
}
public CustomAlertDialogBuilder setCanceledOnTouchOutside (boolean cancelOnTouchOutside) {
mCancelOnTouchOutside = cancelOnTouchOutside;
return this;
}
@Override
public AlertDialog create() {
throw new UnsupportedOperationException("CustomAlertDialogBuilder.create(): use show() instead..");
}
@Override
public AlertDialog show() {
final AlertDialog alertDialog = super.create();
DialogInterface.OnClickListener emptyOnClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) { }
};
// Enable buttons (needed for Android 1.6) - otherwise later getButton() returns null
if (mPositiveButtonText != null) {
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, mPositiveButtonText, emptyOnClickListener);
}
if (mNegativeButtonText != null) {
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, mNegativeButtonText, emptyOnClickListener);
}
if (mNeutralButtonText != null) {
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, mNeutralButtonText, emptyOnClickListener);
}
// Set OnDismissListener if available
if (mOnDismissListener != null) {
alertDialog.setOnDismissListener(mOnDismissListener);
}
if (mCancelOnTouchOutside != null) {
alertDialog.setCanceledOnTouchOutside(mCancelOnTouchOutside);
}
alertDialog.show();
// Set the OnClickListener directly on the Button object, avoiding the auto-dismiss feature
// IMPORTANT: this must be after alert.show(), otherwise the button doesn't exist..
// If the listeners are null don't do anything so that they will still dismiss the dialog when clicked
if (mPositiveButtonListener != null) {
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mPositiveButtonListener.onClick(alertDialog, AlertDialog.BUTTON_POSITIVE);
}
});
}
if (mNegativeButtonListener != null) {
alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mNegativeButtonListener.onClick(alertDialog, AlertDialog.BUTTON_NEGATIVE);
}
});
}
if (mNeutralButtonListener != null) {
alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mNeutralButtonListener.onClick(alertDialog, AlertDialog.BUTTON_NEUTRAL);
}
});
}
return alertDialog;
}
}
EDIT Here is a small example on how to use the CustomAlertDialogBuilder:
// Create the CustomAlertDialogBuilder
CustomAlertDialogBuilder dialogBuilder = new CustomAlertDialogBuilder(context);
// Set the usual data, as you would do with AlertDialog.Builder
dialogBuilder.setIcon(R.drawable.icon);
dialogBuilder.setTitle("Dialog title");
dialogBuilder.setMessage("Some text..");
// Set your buttons OnClickListeners
dialogBuilder.setPositiveButton ("Button 1", new DialogInterface.OnClickListener() {
public void onClick (DialogInterface dialog, int which) {
// Do something...
// Dialog will not dismiss when the button is clicked
// call dialog.dismiss() to actually dismiss it.
}
});
// By passing null as the OnClickListener the dialog will dismiss when the button is clicked.
dialogBuilder.setNegativeButton ("Close", null);
// Set the OnDismissListener (if you need it)
dialogBuilder.setOnDismissListener(new DialogInterface.OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
// dialog was just dismissed..
}
});
// (optional) set whether to dismiss dialog when touching outside
dialogBuilder.setCanceledOnTouchOutside(false);
// Show the dialog
dialogBuilder.show();
Cheers,
Yuvi

- 1,546
- 11
- 12
-
-
Mmm that sounds strange. I'm using that in my app and only buttons where I explicitly call dialog.dismiss() will dismiss the Dialog. On what Android version you are testing? Can you show your code where you used the CustomAlertDialogBuilder? – YuviDroid Mar 04 '12 at 16:28
-
I think it is caused because of this: (call dialog.show() after onClickListener) http://pastebin.com/uLnSu5v7 If I click positiveButton they get dismissed if boolean is true... – Leandros Mar 04 '12 at 16:41
-
I didn't test it using Activity.onCreateDialog(). Probably it cannot work in that way. I will edit the 'answer' to include a small example on how I use it. – YuviDroid Mar 04 '12 at 16:47
-
4This works for me with the current edit! However: One more caveat. Builder.getContext() is only available on API 11+. Add a field `Context mContext` and set it in the constructor instead. – Oleg Vaskevich May 31 '12 at 20:46
Here's something if you are using DialogFragment
- which is the recommended way to handle Dialogs anyway.
What happens with AlertDialog's setButton()
method (and I imagine the same with AlertDialogBuilder
's setPositiveButton()
and setNegativeButton()
) is that the button you set (e.g. AlertDialog.BUTTON_POSITIVE
) with it will actually trigger TWO different OnClickListener
objects when pressed.
The first being DialogInterface.OnClickListener, which is a parameter to setButton()
, setPositiveButton()
, and setNegativeButton()
.
The other is View.OnClickListener, which will be set to automatically dismiss your AlertDialog
when any of its button is pressed - and is set by AlertDialog
itself.
What you can do is to use setButton()
with null
as the DialogInterface.OnClickListener
, to create the button, and then call your custom action method inside View.OnClickListener
. For example,
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
AlertDialog alertDialog = new AlertDialog(getActivity());
// set more items...
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "OK", null);
return alertDialog;
}
Then, you may override the default AlertDialog
's buttons' View.OnClickListener
(which would otherwise dismiss the dialog) in the DialogFragment
's onResume()
method:
@Override
public void onResume()
{
super.onResume();
AlertDialog alertDialog = (AlertDialog) getDialog();
Button okButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
okButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
performOkButtonAction();
}
});
}
private void performOkButtonAction() {
// Do your stuff here
}
You will need to set this in the onResume()
method because getButton()
will return null
until after the dialog has been shown!
This should cause your custom action method to only be called once, and the dialog won't be dismissed by default.

- 510
- 5
- 8
Inspired by Tom's answer, I believe the idea here is:
- Set the
onClickListener
during the creation of the dialog tonull
- Then set a
onClickListener
after the dialog is shown.
You can override the onShowListener
like Tom. Alternatively, you can
- get the button after calling AlertDialog's
show()
- set the buttons'
onClickListener
as follows (slightly more readable I think).
Code:
AlertDialog.Builder builder = new AlertDialog.Builder(context);
// ...
final AlertDialog dialog = builder.create();
dialog.show();
// now you can override the default onClickListener
Button b = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.i(TAG, "ok button is clicked");
handleClick(dialog);
}
});

- 12,476
- 16
- 84
- 127
Super simple Kotlin approach
with(AlertDialog.Builder(this)) {
setTitle("Title")
setView(R.layout.dialog_name)
setPositiveButton("Ok", null)
setNegativeButton("Cancel") { _, _ -> }
create().apply {
setOnShowListener {
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
//Validate and dismiss
dismiss()
}
}
}
}.show()

- 15,188
- 20
- 81
- 121
For pre API 8 i solved the problem using a boolean flag, a dismiss listener and calling dialog.show again if in case the content of the editText wasn´t correct. Like this:
case ADD_CLIENT:
LayoutInflater factoryClient = LayoutInflater.from(this);
final View EntryViewClient = factoryClient.inflate(
R.layout.alert_dialog_add_client, null);
EditText ClientText = (EditText) EntryViewClient
.findViewById(R.id.client_edit);
AlertDialog.Builder builderClient = new AlertDialog.Builder(this);
builderClient
.setTitle(R.string.alert_dialog_client)
.setCancelable(false)
.setView(EntryViewClient)
.setPositiveButton("Save",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
EditText newClient = (EditText) EntryViewClient
.findViewById(R.id.client_edit);
String newClientString = newClient
.getText().toString();
if (checkForEmptyFields(newClientString)) {
//If field is empty show toast and set error flag to true;
Toast.makeText(getApplicationContext(),
"Fields cant be empty",
Toast.LENGTH_SHORT).show();
add_client_error = true;
} else {
//Here save the info and set the error flag to false
add_client_error = false;
}
}
})
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int id) {
add_client_error = false;
dialog.cancel();
}
});
final AlertDialog alertClient = builderClient.create();
alertClient.show();
alertClient
.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
//If the error flag was set to true then show the dialog again
if (add_client_error == true) {
alertClient.show();
} else {
return;
}
}
});
return true;

- 427
- 4
- 14
The answer at this link is a simple solution, and which is compatible right back to API 3. It is very similiar to Tom Bollwitt's solution, but without using the less compatible OnShowListener.
Yes, you can. You basically need to:
- Create the dialog with DialogBuilder
- show() the dialog
- Find the buttons in the dialog shown and override their onClickListener
I made minor adaptions to Kamen's code since I was extending an EditTextPreference.
@Override
protected void showDialog(Bundle state) {
super.showDialog(state);
class mocl implements OnClickListener{
private final AlertDialog dialog;
public mocl(AlertDialog dialog) {
this.dialog = dialog;
}
@Override
public void onClick(View v) {
//checks if EditText is empty, and if so tells the user via Toast
//otherwise it closes dialog and calls the EditTextPreference's onClick
//method to let it know that the button has been pressed
if (!IntPreference.this.getEditText().getText().toString().equals("")){
dialog.dismiss();
IntPreference.this.onClick(dialog,DialogInterface.BUTTON_POSITIVE);
}
else {
Toast t = Toast.makeText(getContext(), "Enter a number!", Toast.LENGTH_SHORT);
t.show();
}
}
}
AlertDialog d = (AlertDialog) getDialog();
Button b = d.getButton(DialogInterface.BUTTON_POSITIVE);
b.setOnClickListener(new mocl((d)));
}
Such fun!
This code will work for you, because i had a simmilar problem and this worked for me. :)
1- Override Onstart() method in your fragment-dialog class.
@Override
public void onStart() {
super.onStart();
final AlertDialog D = (AlertDialog) getDialog();
if (D != null) {
Button positive = (Button) D.getButton(Dialog.BUTTON_POSITIVE);
positive.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
if (edittext.equals("")) {
Toast.makeText(getActivity(), "EditText empty",Toast.LENGTH_SHORT).show();
} else {
D.dismiss(); //dissmiss dialog
}
}
});
}
}

- 80
- 1
- 9
To prevent Dialog box from closing when clicked and it should only close when the internet is available
I am trying to do the same thing, as I don't want the dialog box to be closed until and unless the internet is connected.
Here is my code:
AlertDialog.Builder builder=new AlertDialog.Builder(MainActivity.this); builder.setTitle("Internet Not Connected");
if(ifConnected()){
Toast.makeText(this, "Connected or not", Toast.LENGTH_LONG).show();
}
else{
builder.setPositiveButton("Retry", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
if(!ifConnected())
{
builder.show();
}
}
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
finish();
}
});
builder.show();
}
And here is my Connectivity manager code:
private boolean ifConnected()
{
ConnectivityManager connectivityManager= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
return networkInfo!=null && networkInfo.isConnected();
}

- 7,904
- 4
- 42
- 42

- 79
- 6
-
This is clever, but I get this error message : `The specified child already has a parent. You must call removeView() on the child's parent first` – Dan Chaltiel Aug 05 '18 at 15:45
For ProgressDialogs
To prevent the dialog from being dismissed automatically you have to set the OnClickListener
after the ProgressDialog
is shown, like so:
connectingDialog = new ProgressDialog(this);
connectingDialog.setCancelable(false);
connectingDialog.setCanceledOnTouchOutside(false);
// Create the button but set the listener to a null object.
connectingDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel",
(DialogInterface.OnClickListener) null )
// Show the dialog so we can then get the button from the view.
connectingDialog.show();
// Get the button from the view.
Button dialogButton = connectingDialog.getButton( DialogInterface.BUTTON_NEGATIVE);
// Set the onClickListener here, in the view.
dialogButton.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick ( View v ) {
// Dialog will not get dismissed until you call dismiss() explicitly.
}
});

- 45,245
- 23
- 243
- 245
public class ComentarDialog extends DialogFragment{
private EditText comentario;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = LayoutInflater.from(getActivity());
View v = inflater.inflate(R.layout.dialog_comentar, null);
comentario = (EditText)v.findViewById(R.id.etxt_comentar_dialog);
builder.setTitle("Comentar")
.setView(v)
.setPositiveButton("OK", null)
.setNegativeButton("CANCELAR", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
}
});
return builder.create();
}
@Override
public void onStart() {
super.onStart();
//Obtenemos el AlertDialog
AlertDialog dialog = (AlertDialog)getDialog();
dialog.setCanceledOnTouchOutside(false);
dialog.setCancelable(false);//Al presionar atras no desaparece
//Implementamos el listener del boton OK para mostrar el toast
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(TextUtils.isEmpty(comentario.getText())){
Toast.makeText(getActivity(), "Ingrese un comentario", Toast.LENGTH_SHORT).show();
return;
}
else{
((AlertDialog)getDialog()).dismiss();
}
}
});
//Personalizamos
Resources res = getResources();
//Buttons
Button positive_button = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
positive_button.setBackground(res.getDrawable(R.drawable.btn_selector_dialog));
Button negative_button = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
negative_button.setBackground(res.getDrawable(R.drawable.btn_selector_dialog));
int color = Color.parseColor("#304f5a");
//Title
int titleId = res.getIdentifier("alertTitle", "id", "android");
View title = dialog.findViewById(titleId);
if (title != null) {
((TextView) title).setTextColor(color);
}
//Title divider
int titleDividerId = res.getIdentifier("titleDivider", "id", "android");
View titleDivider = dialog.findViewById(titleDividerId);
if (titleDivider != null) {
titleDivider.setBackgroundColor(res.getColor(R.color.list_menu_divider));
}
}
}

- 177
- 1
- 12
you can add builder.show(); after validation message before return;
like this
public void login()
{
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(R.layout.login_layout);
builder.setTitle("Login");
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int id)
{
dialog.cancel();
}
});// put the negative button before the positive button, so it will appear
builder.setPositiveButton("Ok", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int id)
{
Dialog d = (Dialog) dialog;
final EditText etUserName = (EditText) d.findViewById(R.id.etLoginName);
final EditText etPassword = (EditText) d.findViewById(R.id.etLoginPassword);
String userName = etUserName.getText().toString().trim();
String password = etPassword.getText().toString().trim();
if (userName.isEmpty() || password.isEmpty())
{
Toast.makeText(getApplicationContext(),
"Please Fill all fields", Toast.LENGTH_SHORT).show();
builder.show();// here after validation message before retrun
// it will reopen the dialog
// till the user enter the right condition
return;
}
user = Manager.get(getApplicationContext()).getUserByName(userName);
if (user == null)
{
Toast.makeText(getApplicationContext(),
"Error ethier username or password are wrong", Toast.LENGTH_SHORT).show();
builder.show();
return;
}
if (password.equals(user.getPassword()))
{
etPassword.setText("");
etUserName.setText("");
setLogged(1);
setLoggedId(user.getUserId());
Toast.makeText(getApplicationContext(),
"Successfully logged in", Toast.LENGTH_SHORT).show();
dialog.dismiss();// if every thing is ok then dismiss the dialog
}
else
{
Toast.makeText(getApplicationContext(),
"Error ethier username or password are wrong", Toast.LENGTH_SHORT).show();
builder.show();
return;
}
}
});
builder.show();
}

- 31
- 2
With this code you can prevent dialog from closing when positive button clicked. Also you can implement the same with the negative button.
final AlertDialog alertDialog = alertDialogBuilder
.setCancelable(false)
.setTitle("TITLE");
.setPositiveButton("OK", null)
.setNegativeButton("CANCEL",
(dialog, id) -> {
dialog.cancel();
})
.show();
Button positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
positiveButton.setOnClickListener(v -> {
// check whatever you want
if(checkMyCondition())
dialog.cancel();
})

- 373
- 2
- 11
-
1This is what I was doing, but the dialog closes in any case. Somehow there must be another handler which is attached which dismisses the dialog. – Csaba Toth Jan 25 '23 at 06:54
If you are using material design
I would suggest checking out material-dialogs. It fixed several issues for me related to currently open Android bugs (see 78088), but most importantly for this ticket it has an autoDismiss
flag that can be set when using the Builder
.

- 10,215
- 9
- 69
- 120
Use a custom layout for your DialogFragment
and add a LinearLayout
under your content which can be styled as borderless to match Google Material Design. Then find the newly created buttons and override their OnClickListener
.
Example:
public class AddTopicFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = getActivity().getLayoutInflater();
final View dialogView = inflater.inflate(R.layout.dialog_add_topic, null);
Button saveTopicDialogButton = (Button) dialogView.findViewById(R.id.saveTopicDialogButton);
Button cancelSaveTopicDialogButton = (Button) dialogView.findViewById(R.id.cancelSaveTopicDialogButton);
final AppCompatEditText addTopicNameET = (AppCompatEditText) dialogView.findViewById(R.id.addTopicNameET);
final AppCompatEditText addTopicCreatedByET = (AppCompatEditText) dialogView.findViewById(R.id.addTopicCreatedByET);
saveTopicDialogButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// validate inputs
if(addTopicNameET.getText().toString().trim().isEmpty()){
addTopicNameET.setError("Topic name can't be empty");
addTopicNameET.requestFocus();
}else if(addTopicCreatedByET.getText().toString().trim().isEmpty()){
addTopicCreatedByET.setError("Topic created by can't be empty");
addTopicCreatedByET.requestFocus();
}else {
// save topic to database
Topic topic = new Topic();
topic.name = addTopicNameET.getText().toString().trim();
topic.createdBy = addTopicCreatedByET.getText().toString().trim();
topic.createdDate = new Date().getTime();
topic.save();
AddTopicFragment.this.dismiss();
}
}
});
cancelSaveTopicDialogButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AddTopicFragment.this.dismiss();
}
});
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
builder.setView(dialogView)
.setMessage(getString(R.string.add_topic_message));
return builder.create();
}
}
dialog_add_topic.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:padding="@dimen/activity_horizontal_margin"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorEnabled="true">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/addTopicNameET"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Topic Name"
android:inputType="textPersonName"
android:maxLines="1" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorEnabled="true">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/addTopicCreatedByET"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Created By"
android:inputType="textPersonName"
android:maxLines="1" />
</android.support.design.widget.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:text="@string/cancel"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/cancelSaveTopicDialogButton"
style="@style/Widget.AppCompat.Button.ButtonBar.AlertDialog" />
<Button
android:text="@string/save"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/saveTopicDialogButton"
style="@style/Widget.AppCompat.Button.ButtonBar.AlertDialog" />
</LinearLayout>
</LinearLayout>

- 11,118
- 5
- 63
- 81

- 280
- 2
- 2
Kotlin
val dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_userinput, null)
val dialogBuilder = MaterialAlertDialogBuilder(requireContext(), R.style.AlertDialogTheme)
dialogBuilder.setView(dialogView)
dialogBuilder.setCancelable(false)
dialogBuilder.setPositiveButton("send",null)
dialogBuilder.setNegativeButton("cancel") { dialog,_ ->
dialog.dismiss()
}
val alertDialog = dialogBuilder.create()
alertDialog.show()
val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)
positiveButton.setOnClickListener {
val myInputText = dialogView.etxt_userinput.text.toString().trim()
if(myInputText.isNotEmpty()){
//Do something
}else{
//Prompt error
dialogView.etxt_userinput.error = "Please fill this"
}
}
We just create an AlertDialog
with the dialogBuilder
and then just set the positive button as we want

- 12,319
- 5
- 67
- 77
It could be built with easiest way:
Alert Dialog with Custom View and with two Buttons (Positive & Negative).
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()).setTitle(getString(R.string.select_period));
builder.setPositiveButton(getString(R.string.ok), null);
builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Click of Cancel Button
}
});
LayoutInflater li = LayoutInflater.from(getActivity());
View promptsView = li.inflate(R.layout.dialog_date_picker, null, false);
builder.setView(promptsView);
DatePicker startDatePicker = (DatePicker)promptsView.findViewById(R.id.startDatePicker);
DatePicker endDatePicker = (DatePicker)promptsView.findViewById(R.id.endDatePicker);
final AlertDialog alertDialog = builder.create();
alertDialog.show();
Button theButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
theButton.setOnClickListener(new CustomListener(alertDialog, startDatePicker, endDatePicker));
CustomClickLister of Positive Button of Alert Dailog:
private class CustomListener implements View.OnClickListener {
private final Dialog dialog;
private DatePicker mStartDp, mEndDp;
public CustomListener(Dialog dialog, DatePicker dS, DatePicker dE) {
this.dialog = dialog;
mStartDp = dS;
mEndDp = dE;
}
@Override
public void onClick(View v) {
int day1 = mStartDp.getDayOfMonth();
int month1= mStartDp.getMonth();
int year1 = mStartDp.getYear();
Calendar cal1 = Calendar.getInstance();
cal1.set(Calendar.YEAR, year1);
cal1.set(Calendar.MONTH, month1);
cal1.set(Calendar.DAY_OF_MONTH, day1);
int day2 = mEndDp.getDayOfMonth();
int month2= mEndDp.getMonth();
int year2 = mEndDp.getYear();
Calendar cal2 = Calendar.getInstance();
cal2.set(Calendar.YEAR, year2);
cal2.set(Calendar.MONTH, month2);
cal2.set(Calendar.DAY_OF_MONTH, day2);
if(cal2.getTimeInMillis()>=cal1.getTimeInMillis()){
dialog.dismiss();
Log.i("Dialog", "Dismiss");
// Condition is satisfied so do dialog dismiss
}else {
Log.i("Dialog", "Do not Dismiss");
// Condition is not satisfied so do not dialog dismiss
}
}
}
Done

- 52,124
- 21
- 173
- 151
I found an other way to achieve this...
Step 1: Put the dialog opening code in a method (Or Function in C).
Step 2: Inside the onClick of yes
(Your positiveButton), call this dialog opening
method recursively if your condition is not satisfied (By using if...else...). Like below :
private void openSave() {
final AlertDialog.Builder builder=new AlertDialog.Builder(Phase2Activity.this);
builder.setTitle("SAVE")
.setIcon(R.drawable.ic_save_icon)
.setPositiveButton("Save", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
if((!editText.getText().toString().isEmpty() && !editText1.getText().toString().isEmpty())){
createPdf(fileName,title,file);
}else {
openSave();
Toast.makeText(Phase2Activity.this, "Some fields are empty.", Toast.LENGTH_SHORT).show();
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
}
})
.setCancelable(false)
.create()
.show();
}
But this will make the dialog disappear just for a moment and it will appear again instantly. :)

- 45
- 8
This is probably very late reply, but using setCancelable will do the trick.
alertDial.setCancelable(false);

- 118
- 1
- 6
-
11From the docs: "Sets whether this dialog is cancelable with the BACK key." This has nothing to do with the positive button dismissing the dialog .. – clauziere Apr 12 '16 at 15:51
-
3
-
1
-
2