110

I am developing an application that when the button is pressed, it opens a dialog with OK and Cancel buttons.

It works fine.

When the user presses the back button, I am handling this as follows

public boolean onKeyDown(int keyCode, KeyEvent event) 
{
    if ((keyCode == KeyEvent.KEYCODE_BACK)) 
    {

    }
 return super.onKeyDown(keyCode, event);
}

But the above method is not called. How can I handle this?

Gary
  • 13,303
  • 18
  • 49
  • 71
kiran
  • 3,244
  • 7
  • 34
  • 57

9 Answers9

262
dialog.setOnKeyListener(new Dialog.OnKeyListener() {

            @Override
            public boolean onKey(DialogInterface dialog, int keyCode,
                    KeyEvent event) {                   
                if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
                    finish();
                    dialog.dismiss();
                }
                return true;
            }
        });
WindRider
  • 11,958
  • 6
  • 50
  • 57
Yasin Hassanien
  • 4,055
  • 1
  • 21
  • 17
  • 9
    there's no need to dismiss the `Dialog`; `finish()` takes care of this already. Also, this method probaly should return `false` to be able to capture key events elsewhere – slinden77 May 25 '13 at 07:49
  • 6
    I think alexc's answer below is a better alternative. – Simon Forsberg Sep 24 '13 at 13:25
  • Try Both and choose which is preferred – Yasin Hassanien Oct 03 '13 at 18:24
  • 29
    I added the `&& event.getAction() == KeyEvent.ACTION_UP` to the answer. Without it, the code block will be executed twice. (Key DOWN and key UP). In this example it is not so important, but for other actions than finish(), it might be very important. – Udo Klimaschewski Nov 03 '13 at 13:44
  • 1
    @dmmh if you don't call `dialog.dismiss()` will get a memory leak. – Pedro Lobito Mar 31 '14 at 19:56
  • 2
    I'm sure you're right, but in that case `finish()` and `dialog.dismiss()` should be switched around in the above code. – slinden77 Apr 04 '14 at 09:45
  • 1
    If you return `false`, the event will be catched by the Android framework and it closes the dialog. – Trinimon Sep 15 '14 at 09:35
  • @PedroLobito why is it that not calling `dialog.dismiss()` will cause a memory leak? – Dick Lucas Jan 06 '17 at 16:50
  • @PedroLobito I read it, but I don't see how it shows that failing to call `dialog.dismiss()` before calling `finish()` will produce a memory leak. – Dick Lucas Jan 09 '17 at 18:22
  • Instead of finish(); dialog.dismiss(); only use arg0.dismiss(). That way u dont have to make "dialog", a final variable. And, finish() here would end the current activity as well. Not sure if thats what u wanted. – hariszhr Apr 20 '17 at 06:15
123

Sounds like you want to set the OnCancelListener when you create the Dialog. It looks like this:

dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {         
    @Override
    public void onCancel(DialogInterface dialog) {
        //do whatever you want the back key to do
    }
});
alexc
  • 1,677
  • 1
  • 9
  • 9
  • 8
    This is definitely the best answer. Nice and simple. No need to detect the KeyEvent. Perfect. – LargeGlasses Mar 09 '15 at 16:06
  • 2
    I know I'm too late, but thought to point to something. This additionally will also get triggered when the user clicks somewhere outside the dialog. So if you need to only override the back press option then this is not what you're looking for. – user2520215 Jun 05 '15 at 10:04
  • 6
    @user2520215 if you don't want it to trigger when the user clicks outside the dialog, you should set dialog.setCanceledOnTouchOutside(false). This is definitely the better answer. – Alhassan Abdulkadir Nov 02 '15 at 09:55
  • Thanks for pointing out. This is then surely a better approach. – user2520215 Nov 02 '15 at 12:02
  • 3
    This doesn't seem to work if a custom view is used (i.e. not creating the dialog but just inhering from DialogFragment) while the key listener works in that case. – Julian Honma Aug 25 '17 at 11:07
  • Why does it not work in DialogFragments? Nobody knows :) – Daniel Wilson May 25 '18 at 15:06
  • Okay I'm adding an answer to this for DialogFragments because I've just lost 2 hours to it.. – Daniel Wilson May 25 '18 at 16:11
  • java.lang.IllegalStateException: You can not set Dialog's OnCancelListener or OnDismissListener I see that setOnCancelListener is not allowed. There is a runtime exception on Android 10, Samsung S9. – tuxdost Oct 26 '22 at 21:32
20

You need to override OnCancel method. This method calls on Back Key press. Here's code which works perfect to me.

 AlertDialog alertDialog;

    alertDialog.setOnCancelListener(new OnCancelListener() 
    {                   
           @Override
            public void onCancel(DialogInterface dialog) 
             {
               // TODO Auto-generated method stub

                    dialog.dismiss();                           

            }
}); 

Hope this will help you, and accept it if it is helpful to you.

Thanks..

Never Quit
  • 2,072
  • 1
  • 21
  • 44
9

Try this

 new AlertDialog.Builder(this).setOnKeyListener(new DialogInterface.OnKeyListener() {

                        @Override
                        public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {

                            if(keyCode == KeyEvent.KEYCODE_BACK){
                                Logger.d(TAG, "--------- Do Something -----------");
                                return true;
                            }
                            return false;


                        }
                    })
NitZRobotKoder
  • 1,046
  • 8
  • 44
  • 74
4

If you are using a DialogFragment, from what I can tell the right way to do it is to override onCancel()

I noticed setOnCancelListener does not work, and setOnKeyListener works, but for me has the fun side effect that it swallows all keys if your dialog has an edit text.

Daniel Wilson
  • 18,838
  • 12
  • 85
  • 135
1

it is because when your Dialog opens then your window navigate its focused to Dialog. So now you have to handle key on your Dialog.

Mohammed Azharuddin Shaikh
  • 41,633
  • 14
  • 96
  • 115
1

Override method onBackPressed() in your own dialog and use it in your code:

public class MyDialog extends Dialog {

    public MyDialog(@NonNull Context context) {
        super(context);
    }

    @Override
    public void onBackPressed() {
        // Do what you want
    }
}

Use:

MyDialog dlg = new MyDialog(context);
dlg.show();
1

For Kotlin:

I tried this and that is working fine for me.

dialog.setOnKeyListener { _, keyCode, _ ->
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            //do to task here
        }
        true
    }
Ghayas
  • 1,266
  • 10
  • 17
0

This code works:

    Dialog dlg = new Dialog(thisAct, R.style.DialogTheme);
    dlg.setContentView(view);
    dlg.setCancelable(false);
    dlg.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
    dlg.setOnKeyListener((arg0, keyCode, event) -> {
        Timber.d("onKey(%d)", keyCode);
        //{home intercepting
        if ((keyCode == KeyEvent.KEYCODE_HOME)) {
            Timber.i("HOME pressed");
            return true;
        }

        return true;
    });
    dlg.show();
Andrew Glukhoff
  • 898
  • 11
  • 9