38

I'm working on an accesibility app. When the user wants to leave the app I show a dialog where he has to confirm he wants to leave, if he doesn't confirm after 5 seconds the dialog should close automatically (since the user probably opened it accidentally). This is similar to what happens on Windows when you change the screen resolution (an alert appears and if you don't confirm it, it reverts to the previous configuration).

This is how I show the dialog:

AlertDialog.Builder dialog = new AlertDialog.Builder(this).setTitle("Leaving launcher").setMessage("Are you sure you want to leave the launcher?");
            dialog.setPositiveButton("Confirm", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int whichButton) {
                    exitLauncher();
                }
            });
            dialog.create().show();

How can I close the dialog 5 seconds after showing it?

lisovaccaro
  • 27,544
  • 92
  • 235
  • 388
  • 1
    5 seconds is kind of short. That's not very accessible for people who might be low literacy or for whom English (or whatever language your app is in) is not their first language. There's a somewhat related [article here](http://www.nngroup.com/articles/auto-forwarding/) about accessibility in a situation where the UI changes without user input, like on a timer. – Roddy of the Frozen Peas Jan 21 '13 at 19:29
  • the dialog is not for people with accessibility problems, it's for when the IT guy, eg: grandson takes hold of the phone and want to go the the app settings. So 5 seconds is more than enough. – lisovaccaro Jan 21 '13 at 19:32
  • Then maybe instead of making him confirm he wants to leave, you can make it harder to "accidentally" trigger it? Calling it an 'accessibility app' when it's not actually 'accessible' is rather misleading. I did +1 for a good question; my point is just that 5 seconds is really short. Even Windows on resolution change gives you upwards of 15 seconds to make your decision. – Roddy of the Frozen Peas Jan 21 '13 at 19:34
  • 1
    it's already extremely hard to open the dialog, you have to hold hard buttons for 10 seconds. But I need to be completely sure the user doesn't leave it accidentally. Anyway I will test the best time to hide the dialog, I only picked 5 seconds for the example – lisovaccaro Jan 21 '13 at 19:36

8 Answers8

91
final AlertDialog.Builder dialog = new AlertDialog.Builder(this).setTitle("Leaving launcher").setMessage("Are you sure you want to leave the launcher?");
dialog.setPositiveButton("Confirm", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int whichButton) {
        exitLauncher();
    }
});     
final AlertDialog alert = dialog.create();
alert.show();

// Hide after some seconds
final Handler handler  = new Handler();
final Runnable runnable = new Runnable() {
    @Override
    public void run() {
        if (alert.isShowing()) {
            alert.dismiss();
        }
    }
};

alert.setOnDismissListener(new DialogInterface.OnDismissListener() {
    @Override
    public void onDismiss(DialogInterface dialog) {
        handler.removeCallbacks(runnable);
    }
});

handler.postDelayed(runnable, 10000);
Vladimir Mironov
  • 29,611
  • 3
  • 63
  • 61
  • how can I pass my alertDialog created with AlertDialog.Builder to `final AlertDialog dialog`? – lisovaccaro Jan 21 '13 at 19:44
  • on `dialog.setOnDismissListener` I'm getting this message `Call requires API level 17` API level 17 is like jellybean or something I believe. I need to support everything since API 8 – lisovaccaro Jan 21 '13 at 19:50
  • I asked the first question because I'm also getting `The method dismiss() is undefined for the type AlertDialog.Builder` – lisovaccaro Jan 21 '13 at 19:50
  • 1
    I updated your update. dialog().create().show() returned void. So I changed that line to `final AlertDialog alert = dialog.create();` – lisovaccaro Jan 21 '13 at 20:11
  • When the dialog is open, try rotating the screen. You'll frequently get an "IllegalArgumentException: View not attached to window manager". In the runnable, I use if (winnerDialogue.isShowing() && !isActivityDestroying()) {} And then in the activity, I have private boolean isActivityDestroying() { return this.isDestroying; } @Override protected void onDestroy() { super.onDestroy(); this.isDestroying = true; } – Kenn Nov 02 '13 at 21:50
21

Use CountDownTimer to achieve.

      final AlertDialog.Builder dialog = new AlertDialog.Builder(this)
            .setTitle("Leaving launcher").setMessage(
                    "Are you sure you want to leave the launcher?");
       dialog.setPositiveButton("Confirm",
            new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int whichButton) {
                     exitLauncher();

                }
            });
    final AlertDialog alert = dialog.create();
    alert.show();

    new CountDownTimer(5000, 1000) {

        @Override
        public void onTick(long millisUntilFinished) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onFinish() {
            // TODO Auto-generated method stub

            alert.dismiss();
        }
    }.start();
moDev
  • 5,163
  • 4
  • 31
  • 63
  • I'm getting error: `The method dismiss() is undefined for the type AlertDialog.Builder` – lisovaccaro Jan 21 '13 at 19:41
  • use final AlertDialog.Builder and try it – moDev Jan 21 '13 at 19:46
  • I had changed it to final previously to remove a different warning, I'm still getting the error with dismiss(). It's the only problem with the code. – lisovaccaro Jan 21 '13 at 19:52
  • be very careful with this approach. if the activity is destroyed, it will detect the dialog as having been "leaked". It will schedule the cleanup of the dialog on the ui thread. multiple agents can dismiss the dialog and if they happen in the wrong order your app will crash. – Kenn Nov 02 '13 at 21:45
  • Since `alert` is set to `AlertDialog.Builder` you could use `final AlertDialog alertDialog= alert.create();` then you can `alertDialog.dismiss()` – CrandellWS Jun 04 '16 at 17:01
8

Late, but I thought this might be useful for anyone using RxJava in their application.

RxJava comes with an operator called .timer() which will create an Observable which will fire onNext() only once after a given duration of time and then call onComplete(). This is very useful and avoids having to create a Handler or Runnable.

More information on this operator can be found in the ReactiveX Documentation

// Wait afterDelay milliseconds before triggering call
Subscription subscription = Observable
        .timer(5000, TimeUnit.MILLISECONDS) // 5000ms = 5s
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<Long>() {
            @Override
            public void call(Long aLong) {
                // Remove your AlertDialog here
            }
        });

You can cancel behavior triggered by the timer by unsubscribing from the observable on a button click. So if the user manually closes the alert, call subscription.unsubscribe() and it has the effect of canceling the timer.

drees
  • 5,686
  • 2
  • 24
  • 26
7

This is the code, refer this link:

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // get button
        Button btnShow = (Button)findViewById(R.id.showdialog);
        btnShow.setOnClickListener(new View.OnClickListener() {
            //on click listener
            @Override
            public void onClick(View v) {
                AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
                builder.setTitle("How to close alertdialog programmatically");
                builder.setMessage("5 second dialog will close automatically");
                builder.setCancelable(true);

                final AlertDialog closedialog= builder.create();

                closedialog.show();

                final Timer timer2 = new Timer();
                timer2.schedule(new TimerTask() {
                    public void run() {
                        closedialog.dismiss(); 
                        timer2.cancel(); //this will cancel the timer of the system
                    }
                }, 5000); // the timer will count 5 seconds....

            }
        });
    }
}

HAPPY CODING!

mergenchik
  • 1,109
  • 16
  • 27
dondondon
  • 743
  • 6
  • 4
3
AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(R.string.game_message);
        game_message = builder.create();
        game_message.show();


        final Timer t = new Timer();
        t.schedule(new TimerTask() {
            public void run() {
                game_message.dismiss(); // when the task active then close the dialog
                t.cancel(); // also just top the timer thread, otherwise, you may receive a crash report
            }
        }, 5000);

Reference : https://xjaphx.wordpress.com/2011/07/13/auto-close-dialog-after-a-specific-time/

Tahirhan
  • 192
  • 1
  • 12
1

I added automatic dismiss with the time remaining shown in the positive button text to an AlertDialog.

AlertDialog dialog = new AlertDialog.Builder(getContext())
        .setTitle(R.string.display_locked_title)
        .setMessage(R.string.display_locked_message)
        .setPositiveButton(R.string.button_dismiss, null)
        .create();

dialog.setOnShowListener(new DialogInterface.OnShowListener() {
    @Override
    public void onShow(DialogInterface dialog) {
        final Button positiveButton = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE);
        final CharSequence positiveButtonText = positiveButton.getText();
        new CountDownTimer(AUTO_DISMISS_MILLIS, 100) {
            @Override
            public void onTick(long millisUntilFinished) {
                positiveButton.setText(String.format(Locale.getDefault(), "%s (%d)",
                        positiveButtonText,
                        TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) + 1));
            }

            @Override
            public void onFinish() {
                dismiss();
            }
        }.start();

    }
});
Jon
  • 7,185
  • 6
  • 45
  • 66
1

For Kotlin inspired by Tahirhan's answer. This is what worked for my current project. Hope it will help someone else in the near future. Im calling this function in a fragment. Happy coding!

 fun showAlert(message: String) {
        val builder = AlertDialog.Builder(activity)
        builder.setMessage(message)

        val alert = builder.create()
        alert.show()

        val timer = Timer()
        timer.schedule(object : TimerTask() {
            override fun run() {
                alert.dismiss()
                timer.cancel()
            }
        }, 5000)
    }
-6
AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create();

then call dismiss meth it work

alertDialog .dismiss(); 
Aleksandr M
  • 23,647
  • 12
  • 63
  • 129