Android Confirmation dialog returning true or false
Asked Answered
S

8

12

It seems to be there is no easy way to get an Alert dialog to return a simple value.
This code does not work (the answer variable cannot be set from within the listener, in fact it does not even compile)

public static boolean Confirm(Context context) {
    boolean answer;
    AlertDialog dialog = new AlertDialog.Builder(context).create();
    dialog.setTitle("Confirmation");
    dialog.setMessage("Choose Yes or No");
    dialog.setCancelable(false);
    dialog.setButton(DialogInterface.BUTTON_POSITIVE, "Yes", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int buttonId) {
            answer = true;
        }
    });
    dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "No", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int buttonId) {
            answer = false;
        }
    });
    dialog.setIcon(android.R.drawable.ic_dialog_alert);
    dialog.show();
    return answer;
}

NOTE: It is important that the method is self contained, i.e., it does not depend on variables or constructs external to it. Just call it and get your answer, true or false.

So, what to do? This simple wish of returning true or false seems to be much more complicated than it deserves.

Also, the setButton method has the form:

dialog.setButton(int buttonId, String buttonText, Message msg)

But it is not clear how to use it, where is the meesage sent to, to whom, which handler is used?

Spicer answered 26/5, 2012 at 5:56 Comment(0)
S
10

Well, I was going to say that I am very pleased with myself because I found a simple answer, all by myself!
But the truth is that although I find a way to return a value (which I show below). It is of no use.

The real problem is I wanted a synchronous Dialog, a dialog that waits for the user to answer before resuming your code after dialog.show().
There is no such beast in Android. All dialogs are asynchronous, so dialog.show() only posts the dialog in some queue (I think) and continues. Thus you don't get your answer in time.

For all its worth (nothing) below you'll find how to set a value inside the method that builds the dialog. Maybe there are other uses for this technique, not related to the dialog lifecycle.




To give some related info, I'll say that if you replace

boolean answer;

with

final boolean answer;

it is possible to access the variable from within the listener, but it is not possible to assign it a new value, since it was declared as final.

Here comes the trick.
Define the variable as:

final boolean[] answer = new boolean[1];

Some of you already see why this will work. The final variable here is not the single element of the boolean array, is the array itself.
So now you can assign the array element [0] as you wish.

dialog.setButton(DialogInterface.BUTTON_POSITIVE, "Yes", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int buttonId) {
        answer[0] = true;
    }
});
. . .
return answer[0];

And finally you can return it from your method.

Spicer answered 26/5, 2012 at 14:34 Comment(5)
You ever find a better solution?Gee
@Gee As I stated, this is not really a solution and I explainded why with the current Android OS there cannot be a soultion. So, in short, I did not find a better solution. According to Android, you should put your code inside the onClick() listener for the dialog. That's the only way to execute it after you close the dialog.Spicer
iLomambo Did you try the one up top with calling RunnableGee
I have moved since to other projects, so I have not tried it. But if you understand my answer it is pretty obvious how it's going to behave. Because of the asynchronous character of Android, the moment you call show() the dialog is displayed and the code moves on, it does not wait for the user click on OKSpicer
right but if there is nothing else in the code but for example onClick(dialog(proca(), procb()) the screen will only change after a selection regardless of async because in procA I tell it what to do and that wont get executed unless it is told to run in the dialogGee
D
18

i have post similiar problem in this forum, but finally i get my answer. my problem in that post is how to create separate confirm dialog class who can acces by other class or activity, so with that confirm dialog class we don't need to write long coding.

here's my answer.

First you must create DialogHandler.java

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import src.app.R;

public class DialogHandler {
    public Runnable ans_true = null;
    public Runnable ans_false = null;

    // Dialog. --------------------------------------------------------------

    public boolean Confirm(Activity act, String Title, String ConfirmText,
            String CancelBtn, String OkBtn, Runnable aProcedure, Runnable bProcedure) {
        ans_true = aProcedure;
        ans_false= bProcedure;
        AlertDialog dialog = new AlertDialog.Builder(act).create();
        dialog.setTitle(Title);
        dialog.setMessage(ConfirmText);
        dialog.setCancelable(false);
        dialog.setButton(DialogInterface.BUTTON_POSITIVE, OkBtn,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int buttonId) {
                         ans_true.run();
                    }
                });
        dialog.setButton(DialogInterface.BUTTON_NEGATIVE, CancelBtn,
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int buttonId) {
                        ans_false.run();
                    }
                });
        dialog.setIcon(android.R.drawable.ic_dialog_alert);
        dialog.show();
        return true;
    }
}

And this is example to call it in another class

public class YourActivity extends Activity {
    /** Called when the activity is first created. */

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        findViewById(R.id.button1).setOnClickListener(myclick);
    }

    public final Button.OnClickListener myclick = new Button.OnClickListener() {
        @Override
        public void onClick(View v) {
            doclick();
        }
    };

    public void doclick() {
        DialogHandler appdialog = new DialogHandler();
        appdialog.Confirm(this, "Message title", "Message content",
                "Cancel", "OK", aproc(), bproc());
    }

    public Runnable aproc(){
        return new Runnable() {
            public void run() {
                Log.d("Test", "This from A proc");
            }
          };
    }

    public Runnable bproc(){
        return new Runnable() {
            public void run() {
                Log.d("Test", "This from B proc");
            }
          };
    }


}
Dulles answered 19/11, 2012 at 3:24 Comment(4)
@Lion789 See my response to your comment in my own answer. The real test here is: put some code in the onClick() method after invoking doClick() to check the user response to the DialogHandler dialog and see if that code execution waits for the dialog to close. I think it will not.Spicer
I like your approach and it is running . I have checked it.Influx
@Roro Great job. It works. This should be the accepted answerArdys
@Dulles Nice logic..Works nicely. This one indeed needs to be the accepted answer.Wombat
S
10

Well, I was going to say that I am very pleased with myself because I found a simple answer, all by myself!
But the truth is that although I find a way to return a value (which I show below). It is of no use.

The real problem is I wanted a synchronous Dialog, a dialog that waits for the user to answer before resuming your code after dialog.show().
There is no such beast in Android. All dialogs are asynchronous, so dialog.show() only posts the dialog in some queue (I think) and continues. Thus you don't get your answer in time.

For all its worth (nothing) below you'll find how to set a value inside the method that builds the dialog. Maybe there are other uses for this technique, not related to the dialog lifecycle.




To give some related info, I'll say that if you replace

boolean answer;

with

final boolean answer;

it is possible to access the variable from within the listener, but it is not possible to assign it a new value, since it was declared as final.

Here comes the trick.
Define the variable as:

final boolean[] answer = new boolean[1];

Some of you already see why this will work. The final variable here is not the single element of the boolean array, is the array itself.
So now you can assign the array element [0] as you wish.

dialog.setButton(DialogInterface.BUTTON_POSITIVE, "Yes", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int buttonId) {
        answer[0] = true;
    }
});
. . .
return answer[0];

And finally you can return it from your method.

Spicer answered 26/5, 2012 at 14:34 Comment(5)
You ever find a better solution?Gee
@Gee As I stated, this is not really a solution and I explainded why with the current Android OS there cannot be a soultion. So, in short, I did not find a better solution. According to Android, you should put your code inside the onClick() listener for the dialog. That's the only way to execute it after you close the dialog.Spicer
iLomambo Did you try the one up top with calling RunnableGee
I have moved since to other projects, so I have not tried it. But if you understand my answer it is pretty obvious how it's going to behave. Because of the asynchronous character of Android, the moment you call show() the dialog is displayed and the code moves on, it does not wait for the user click on OKSpicer
right but if there is nothing else in the code but for example onClick(dialog(proca(), procb()) the screen will only change after a selection regardless of async because in procA I tell it what to do and that wont get executed unless it is told to run in the dialogGee
R
5

What you can do is create a Listener for your Alert Dialog that listens to AlertDialogs action using an Interface.

Create an Interface.

public class MyInterface {

    DialogReturn dialogReturn;

    public interface DialogReturn {

        void onDialogCompleted(boolean answer);
    }

    public void setListener(DialogReturn dialogReturn) {
        this.dialogReturn = dialogReturn;
    }

    public DialogReturn getListener() {
        return dialogReturn;

    }
}

Now, in your class just implement the Interface that you created using implements MyInterface.DialogReturn

then you can set the Listener and get it working as show below,

public class Main extends Activity implements MyInterface.DialogReturn{

    MyInterface myInterface;
    MyInterface.DialogReturn dialogReturn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
                ....
        myInterface = new MyInterface();
        myInterface.setListener(this);
    }


   public void Confirm(Context context) {
        AlertDialog dialog = new AlertDialog.Builder(context).create();
        dialog.setTitle("Confirmation");
        dialog.setMessage("Choose Yes or No");
        dialog.setCancelable(false);
        dialog.setButton(DialogInterface.BUTTON_POSITIVE, "Yes", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int buttonId) {
                myInterface.getListener().onDialogCompleted(true);
            }
        });
        dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "No", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int buttonId) {
                myInterface.getListener().onDialogCompleted(false);
            }
        });
        dialog.setIcon(android.R.drawable.ic_dialog_alert);
        dialog.show();
         }


@Override
    public void onDialogCompleted(boolean answer) {
        Toast.makeText(Main.this, answer+"", Toast.LENGTH_LONG).show();
            if(answer)
            // do something
            else
            // do something
    }
}
Randalrandall answered 26/5, 2012 at 6:38 Comment(3)
I am assuming your suggestion works. But, what a complicated way to achieve a simple thing ! Don't you think?Spicer
Ya true, but this is not that much complicated if we understand it once and get it working.Randalrandall
@Spicer <unsolicitedEditorial>Welcome to Android! Welcome to Java for that matter.</unsolicitedEditorial>Screw
S
1

I find that using jDeferred helps in cases where you want to wait for input.

It is essentially equivalent to using an interface, but instead you create done and fail handlers. Just an alternative to consider:

new ConfirmationDialog(mContext)
        .showConfirmation("Are you sure?", "Yes", "No")
        .done(new DoneCallback<Void>() {
            @Override
            public void onDone(Void aVoid) {
                ....
            }
        })
        .fail(new FailCallback<Void>() {

            @Override
            public void onFail(Void aVoid) {
                ...
            }
        });

Implementation:

public class ConfirmationDialog {


    private final Context mContext;
    private final DeferredObject<Void, Void, Void> mDeferred = new DeferredObject<Void, Void, Void>();

    public ConfirmationDialog(Context context) {
        mContext = context;
    }

    public Promise<Void, Void, Void> showConfirmation(String message, String positiveButton, String negativeButton) {
        AlertDialog dialog = new AlertDialog.Builder(mContext).create();
        dialog.setTitle("Alert");
        dialog.setMessage(message);
        dialog.setCancelable(false);
        dialog.setButton(DialogInterface.BUTTON_POSITIVE, positiveButton, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int buttonId) {
                mDeferred.resolve(null);
            }
        });
        dialog.setButton(DialogInterface.BUTTON_NEGATIVE, negativeButton, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int buttonId) {
                mDeferred.reject(null);
            }
        });
        dialog.setIcon(android.R.drawable.ic_dialog_alert);
        dialog.show();
        return mDeferred.promise();
    }

}
Screw answered 26/9, 2013 at 23:13 Comment(0)
R
1

With Andriod, it is not a good idea to block the running thread by waiting for the user to say 'yes' or 'no'.

In order to ask for a confirmation, you can define a method that receives an AsynTask. The method executes that task if the user press the confirm button.

For example:

    //this method displays a confirm dialog. If 'yes' answer, runs 'yesTask', 
    //if 'no' answer, runs 'noTask'
    //notice than 'yesTask' and 'noTask' are AysncTask
    //'noTask' can be null, example: if you want to cancel when 'no answer'

    public static void confirm(Activity act, String title, String confirmText,
                       String noButtonText, String yesButtonText,
                       final AsyncTask<String, Void, Boolean> yesTask,
                       final AsyncTask<String, Void, Boolean> noTask) {

    AlertDialog dialog = new AlertDialog.Builder(act).create();
    dialog.setTitle(title);
    dialog.setMessage(confirmText);
    dialog.setCancelable(false);
    dialog.setButton(DialogInterface.BUTTON_POSITIVE, yesButtonText,
        new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int buttonId) {
                yesTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
            }
        });
    dialog.setButton(DialogInterface.BUTTON_NEGATIVE, noButtonText,
        new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int buttonId) {
                if(noTask!=null) {
                    noTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                }

            }
        });
    dialog.setIcon(android.R.drawable.ic_dialog_alert);
    dialog.show();
}

You can call it from your activity with:

 YourTask yourTask =  new YourTask( ... );
 confirm( YourActivity.this, 
         "Confirm", 
         "Are you sure?", 
         "Cancel", 
         "Continue", 
         yourTask,
         null);

YourTask class must extend AsyncTask

Rivi answered 18/4, 2015 at 12:30 Comment(0)
B
0

Declare a field 'answer' in your activity and set a value to it. Fields of a class are visible to inner classes, so you can do that.

Barrybarrymore answered 26/5, 2012 at 6:3 Comment(1)
Yes.. I did not mention it, but I need the method to be independent of the class it is defined in. Cannot use a class variable. I will update the question to make it clearer.Spicer
F
0

I was also struggling to use a blocking confirm dialog and I finally did it using a BlockingQueue :

public static class BlockingConfirmDialog{

    private Activity context;

    BlockingQueue<Boolean> blockingQueue;

    public BlockingConfirmDialog(Activity activity) {
        super();
        this.context = activity;
        blockingQueue = new ArrayBlockingQueue<Boolean>(1);
    }

    public boolean confirm(final String title, final String message){

        context.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                new AlertDialog.Builder(context)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) { 
                        blockingQueue.add(true);
                    }
                 })
                 .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        blockingQueue.add(false);
                    }
                })
                 .show();
            }
        });

        try {
            return blockingQueue.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }

    }
}
Fivefinger answered 5/8, 2013 at 14:47 Comment(0)
L
0

I've tried all of the solutions and the easier and cleanest is by far the first solution with the Runnable, in my opinion. It supports the dialog on the Cancel button listener, the OnBAckPressed() and the onOptionsItemSelected().

The code as described though calls the ans_false.run(); when clicking the BUTTON_POSITIVE and the ans_true.run(); when clicking the BUTTON_NEGATIVE.

Here is the code I used to fix that problem:

public class MyDialogs {

// private constructor
public Runnable answerTrue = null;
public Runnable answerFalse = null;

// Dialog. --------------------------------------------------------------

public boolean confirm(Activity act, String Title, String ConfirmText,
                       String noBtn, String yesBtn, Runnable yesProc, Runnable noProc) {
    answerTrue = yesProc;
    answerFalse= noProc;
    AlertDialog.Builder alert = new AlertDialog.Builder(act);
    alert.setTitle(Title);
    alert.setMessage(ConfirmText);
    alert.setCancelable(false);
    alert.setPositiveButton(R.string.button_positive, new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            answerTrue.run();
        }
    });
    alert.setNegativeButton(R.string.button_negative, new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            answerFalse.run();
        }
    });
    alert.show().getButton(DialogInterface.BUTTON_NEGATIVE).requestFocus();
    return true;
}

}

Lots answered 16/6, 2017 at 1:6 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.