5

I am trying to show a messagebox with OK button. I am using AlertDialog for this purpose and I realised that it is not blocking the code. Example:

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

       new AlertDialog.Builder(this).setTitle("Test dlg").setMessage("Alert 1")
        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {}
        })
        .setNegativeButton("", null)
        .show();

       new AlertDialog.Builder(this).setTitle("Test dlg").setMessage("Alert 2")
       .setPositiveButton("OK", new DialogInterface.OnClickListener() {
           @Override
           public void onClick(DialogInterface dialog, int which) {}
       })
       .setNegativeButton("", null)
       .show();
        //...continue with UI initialization here...
    }

When I start activity, it shows Alert2, When I press ok it shows Alert1 afterwards.

I need to have blocking code dialog, so at first it should show Alert1 message, wait until user presses OK button then continue to execute the code and show Alert2 message, etc.. Example:

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
      msgBox("Test dlg", "Alert 1");
      msgBox("Test dlg", "Alert 2");
      //...continue with UI initialization here...
    }


private void msgBox(String title, String msg){

   //?????

   /*  WRONG, NON-BLOCKING
   new AlertDialog.Builder(this).setTitle(title).setMessage(msg)
        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {}
        })
        .setNegativeButton("", null)
        .show();
   */
}

What should I write on //????? place in msgBox method?

MORE EXAMPLE, I need something like this:

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
   if (isInitialisationDataFailed()){
      msgBox("Alert", "Cannot open activity, sorry");
      myActivity.this.finish();
      return;
    }
}

But this does not work. Activity finish runs quicker than alert appear on the screen.

The main idea to have messagebox code separate to own method to make it reusable. How to achieve this?

///////////////////////////////// another example:

private void init(){
  //init code here...
  if (isSomethingWhrong()){
    msgbox("wrong stuff will be fixed");
    //do fix wrong stuff here...
  }
  if (isAnotherthingWrong()){
    msgbox("more wrong stuff will be fixed");
    //do fix more wrong stuff....
  }
  //continue init code here...
}

private void msgbox(String msg){
    //BLOCKING DIALOG REALISATION here...
}

and as alternative this:

private void init(){
  //init code here...
  handleWrongStuff();
}
private void handleWrongStuff(){
 if (isSomethingWhrong()){
   new AlertDialog.Builder(activity)
        .setTitle("Test")
        .setMessage("wrong stuff will be fixed")
        .setPositiveButton("OK", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                 //do fix wrong stuff here...
                 handleMoreWrongStuff();       
            }

        })
        .setNegativeButton("", null)
        .show();
 }
  else{
     handleMoreWrongStuff();   
  }
}

private void handleMoreWrongStuff(){
 if (isAnotherthingWrong()){
   new AlertDialog.Builder(activity)
        .setTitle("Test")
        .setMessage("more wrong stuff will be fixed")
        .setPositiveButton("OK", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                 //do fix more wrong stuff here...    
                 continueInit();  
            }

        })
        .setNegativeButton("", null)
        .show();
 }
  else{
    continueInit();  
  }
}

private void continueInit(){
  //continue init code here...
}

do you see the difference in complexity? In order to make init code working in Android I need to split it to separate methods but not on logical blocks but when I need to show dialogs. Moreover the code for initialization dialogs are repeated and became ugly and unreadable.

kompotFX
  • 353
  • 2
  • 4
  • 13
  • I see the difference and if that is the functionality you want - then the last block of code you posted is the solution - as I mentioned Android Dialogs do not block execution. I however still don't see why you want to bother the user with dialogs. If wrong stuff happens then fix it. A user won't care about wrong stuff unless it prevents them from using the app. – kaspermoerch Oct 04 '11 at 09:45
  • no, I dont want exactly this functionality, it's just an example. My case right now: onCreate of activity I check integrity of data and if it wrong, I go back (finish activity) and display to user dialog "cannot open this form" before closing it. Because of non-bloking behaviour I need to write dialog code inside onCreate, and split the rest of onCreate code to separate method. And this message box "onClick()" implementation i need write all over again and again if I need it in different activities. That's nasty. – kompotFX Oct 04 '11 at 09:57
  • possible duplicate of [Android: wait on user input from dialog?](http://stackoverflow.com/questions/4381296/android-wait-on-user-input-from-dialog) and http://stackoverflow.com/questions/2028697/dialogs-alertdialogs-how-to-block-execution-while-dialog-is-up-net-style/2029128#2029128 – CommonsWare Oct 04 '11 at 11:18
  • take a look on "another example" section. The first sample is how it is done on other platforms: one logical method "init" and one helper "msgbox" reused anywhere in code by one line call. The second sample is android one: "init" split to several parts with several repeated dialog code and ugly unreadable chain construction. – kompotFX Oct 04 '11 at 11:59

8 Answers8

4

Put the code to show 2nd dialog in onClick of Positive button of First alert dialog.

anujprashar
  • 6,263
  • 7
  • 52
  • 86
  • 1
    I need to wait for dialog to be closed and then continue with the rest of the code rather than shuffle with dialogs. – kompotFX Oct 04 '11 at 07:54
  • Thats why I am saying put your code which you want to execute in ok button of dialog. It wont get executed until you press ok button. – anujprashar Oct 04 '11 at 07:59
  • by your advise it mean that I have to put all the rest of onCreate code in onClick method. Now imagine than during initialization I will need maybe to show 5 dialogs. Imagine how the code will look like. I need "flat" structure for my code with simple "OK" messageboxes. – kompotFX Oct 04 '11 at 08:11
  • Then put the next bit of your initialisation code into a method and execute this method when the user clicks the "OK" button. Where is the problem in this? So it will be like this: code -> alertdialog -> ok-buttonclick -> code -> alertdialog ... – banzai86 Oct 04 '11 at 10:37
  • 1
    The problem is that this kind of code is unreadable and ugly. Maybe it is ok in java, but after many years of coding in other languages it's looks "not user friendly" for me. – kompotFX Oct 04 '11 at 11:03
  • 1
    how is this code "uglier" than your code? In Android dialogs are defined in `protected Dialog onCreateDialog(int id) {}`, then you show them with `dialog.show(intValueOfYourDialog)`. That's simple and clean – banzai86 Oct 04 '11 at 11:21
2

using this way you can't stop the execution but instead of this you can put on button action listener so when button pressed at that time listener will be invoked and you can execute the code for e.g. in your case when you press the ok button then show the next alert from listener.

    new AlertDialog.Builder(this).setTitle("Test dlg").setMessage("Alert 1")
    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
               new AlertDialog.Builder(YourActivity.this).setTitle("Test dlg").setMessage("Alert 2")
              .setPositiveButton("OK", new DialogInterface.OnClickListener() {
               @Override
               public void onClick(DialogInterface dialog, int which) {}
               })
             .setNegativeButton("", null)
             .show();
        }
    })
    .setNegativeButton("", null)
    .show();
Pratik
  • 30,639
  • 18
  • 84
  • 159
  • but this solution leads to an ugly nested tree code especially if I will have more dialogs to show. I need to separate dialog code execution to own method in order have readable code. And still the code after dialog not prevented from execution. – kompotFX Oct 04 '11 at 07:49
  • there is no another way. because when the execution start it can't wait(until to use like sleep() or equivalent) but if you can put sleep then also it will sleep for the specific time then execute the rest of code – Pratik Oct 04 '11 at 08:07
1

This is a late answer, but may give you closure.

The cleanest way to do what you want is to launch an activity instead of the dialog. A simple activity with just one OK button.

When the OK button is pressed just close the activity.
If you need more complex responses, more buttons, text input, etc.
use StartActivityWithResult() to return the user's choice

ilomambo
  • 8,290
  • 12
  • 57
  • 106
1

Dialogs do not block code execution - pretty simple. The only way to achieve a "block-like" behaviour is to split execution-chain into smaller bits.

Lets assume you want to show a total of five Dialogs during UI-initialization. In your Activity, you create the following methods:

private void beforeFirstDialog() {
   // Do the initialization until you want the first dialog
   // Show the first dialog
   // When clicking 'OK' in the first dialog, beforeSecondDialog() is called.
}

private void beforeSecondDialog() {
   // Do the initialization until you want the second dialog
   // Show the second dialog
   // When clicking 'OK' in the second dialog, beforeThirdDialog() is called.
}

private void beforeThirdDialog() {
   // Do the initialization until you want the third dialog
   // Show the third dialog
   // When clicking 'OK' in the third dialog, beforeFourthDialog() is called.
}

private void beforeFourthDialog() {
   // Do the initialization until you want the fourth dialog
   // Show the fourth dialog
   // When clicking 'OK' in the first dialog, beforeFifthDialog() is called.
}

private void beforeFifthDialog() {
   // Do the initialization until you want the fifth dialog
   // Show the fifth dialog
   // When clicking 'OK' in the first dialog, afterFifthDialog() is called.
}

private void afterFifthDialog() {
   // Do what needs to be done after the last dialog.
}
kaspermoerch
  • 16,127
  • 4
  • 44
  • 67
  • ohh, ok, so there is no way in android to write clean and readable code for this dialogs? Is there anything else instead of AlertDialog to can make code simple? – kompotFX Oct 04 '11 at 08:34
  • That is 100% dependable on what you want to do. What you could consider is if so many dialogs are really needed? Maybe you could replace it with just one dialog or maybe even an Activity that saves the preferences for you. Maybe you need to use a ViewFlipper and then have different layouts inflated that you can change between. Personally I hate dialogs (they make me wait or require my interaction, which I don't like) but in some cases they are needed - in other cases they're not. – kaspermoerch Oct 04 '11 at 08:50
  • check ///////////////////////////////// another example I added. – kompotFX Oct 04 '11 at 09:40
0

As you (might have) discovered from the many replies that you should not block the Main UI Thread. However, if you have a very good reason to block the code while you get a response from the user, then you could create a thread where you loop/wait for the user input while you the AlertDialog is displayed via the MainUI Thread. I have a full blog post here that explains this

protected void RunConfirmAction(Action runnableAction)
{
    var confirmThread = new Thread(() => runnableAction());
    confirmThread.Start();
}

// OnClick (when the user clicks Logout Button, I call this
RunConfirmAction(Logout);

// the implemtation of the MessageBox waiting looks like this:
public DialogResult MessageBoxShow(string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton)
{
    if (_CurrentContext != null && MainActivity != null)
    {
        Action<bool> callback = OnConfirmCallBack;
        _IsCurrentlyInConfirmProcess = true;
        Action messageBoxDelegate = () => MessageBox.Show(((Activity)MainActivity), callback, message, caption, buttons);
        RunOnMainUiThread(messageBoxDelegate);
        while (_IsCurrentlyInConfirmProcess)
        {
            Thread.Sleep(1000);
        }               
    }
    return _ConfirmBoxResult ? DialogResult.OK : DialogResult.No;
}

private void OnConfirmCallBack(bool confirmResult)
{
    _ConfirmBoxResult = confirmResult;
    _IsCurrentlyInConfirmProcess = false;
}

private bool _ConfirmBoxResult = false;
private bool _IsCurrentlyInConfirmProcess = false;

I hope this can help somebody, the full details of the solution can be found here

Has AlTaiar
  • 4,052
  • 2
  • 36
  • 37
0

Kotlin makes life easy, call within a co-routine

suspendCoroutine<Context> { cont ->
     runOnUiThread {
            val builder = androidx.appcompat.app.AlertDialog.Builder(this@YourScreen)
            builder.setTitle("Title")
            builder.setMessage("I have a message for you")
            builder.setPositiveButton("Yes") { _, _ ->
                   /* Do something on yes */
            }
            builder.setNegativeButton("No") { _, _ ->
                   /* Do something on no */
            }
            builder.setOnCancelListener {
                  cont.resume(this@YourScreen)
            }
            val askdialog = builder.create()
            askdialog.show()
     }
}
//Code will continue here
Rowan Berry
  • 171
  • 7
0

under the conditon give this.

ShowAlert.displayAlert(the present class name.this,"Please enter the error message");

          strDomain.requestFocus();

create a new class ShowAlert, inside that put this code.

public class ShowAlert {

    public static void displayAlert(Activity act,String msg)
    {
        AlertDialog.Builder alert = new AlertDialog.Builder(act);
        alert.setMessage(msg).setPositiveButton("OK", new DialogInterface.OnClickListener(){
             @Override
             public void onClick(DialogInterface dialog, int which)
             {   

             }
             })
             .show();
    }

}
DAS
  • 686
  • 8
  • 13
  • but ShowAlert.displayAlert() does not prevent from rest of code execution. It does not wait until user click on OK button. – kompotFX Oct 04 '11 at 10:37
  • yes it does.first you have to make the ShowAlert class with the code and then inside you class where you wnat to prevent the code from execution until the ok button is pressed use the below code: ShowAlert.displayAlert(the present class name.this,"Please enter the error message"); strDomain.requestFocus(); – DAS Oct 04 '11 at 10:55
  • it does not work for me. Code continue execute futher not waiting for me to click OK button. Is this "strDomain.requestFocus()" does the trick? what is "strDomain"? its not part of activity class. It gives me compile error. – kompotFX Oct 04 '11 at 11:07
  • EditText strDomain; strDomain is the edittext name. it like when that field is null i have made it like unless it is filled it will not go to the next page.. what is your case when you want to show the message at want instance? – DAS Oct 04 '11 at 11:34
0

EditText strDomain;

strDomain is the edittext name. it like when that field is null i have made it like unless it is filled it will not go to the next page.. what is your case when you want to show the message at want instance?

DAS
  • 686
  • 8
  • 13
  • I see your case. Try to write ShowAlert.displayAlert(this, "alert1"); ShowAlert.displayAlert(this, "Alert2"); line by line and you will see that first message you see on the screen is "Alert2". – kompotFX Oct 04 '11 at 11:37
  • according all info I got, your code cannot work "correctly". When you call A and then B in dialogs, you will see on screen B, then when click OK you will see A – kompotFX Oct 04 '11 at 12:03
  • strDomain that i have used is like it will return the fous back to that area. although the code works for me.. I believe that you have made something wrong in some place, any way you got it rite. – DAS Oct 04 '11 at 12:09