88

I wrote a piece of code that will give the user a prompt asking them to press back again if they would like to exit. I currently have my code working to an extent but I know it is written poorly and I assume there is a better way to do it. Any suggestions would be helpful!

Code:

public void onBackPressed(){
    backpress = (backpress + 1);
    Toast.makeText(getApplicationContext(), " Press Back again to Exit ", Toast.LENGTH_SHORT).show();

    if (backpress>1) {
        this.finish();
    }
}
Ojonugwa Jude Ochalifu
  • 26,627
  • 26
  • 120
  • 132
Nick
  • 9,285
  • 33
  • 104
  • 147
  • 7
    Replace `this.finish()` with `super.onBackPressed();`. – Fred Apr 10 '14 at 16:42
  • 5
    instead of `this.finish()` rather call `NavUtils.navigateUpFromSameTask(this);` to get back to previous screen/ activity – To Kra Mar 30 '15 at 17:49

13 Answers13

221

I would implement a dialog asking the user if they wanted to exit and then call super.onBackPressed() if they did.

@Override
public void onBackPressed() {
    new AlertDialog.Builder(this)
        .setTitle("Really Exit?")
        .setMessage("Are you sure you want to exit?")
        .setNegativeButton(android.R.string.no, null)
        .setPositiveButton(android.R.string.yes, new OnClickListener() {

            public void onClick(DialogInterface arg0, int arg1) {
                WelcomeActivity.super.onBackPressed();
            }
        }).create().show();
}

In the above example, you'll need to replace WelcomeActivity with the name of your activity.

Goku
  • 9,102
  • 8
  • 50
  • 81
Steve Prentice
  • 23,230
  • 11
  • 54
  • 55
  • this works, but in my case the popup is showed only for few millisecond and after disappear and the new window is showed. I don't have the time to click yes or no, and if I debug it, it doesn't pass for onClick method. Why? – Accollativo Oct 03 '13 at 14:07
  • 4
    @Accollativo, sounds like you still have a call to `super.onBackPressed()` in your `onBackPressed()` definition (other than the one inside the onClick method)? – Steve Prentice Oct 03 '13 at 15:13
  • 6
    Every app I've seen favors the "second back press" method. A user accidentally hitting the back key will get annoyed if a dialog shows. The toast is less intrusive. – Karmic Coder Jun 06 '14 at 16:43
  • @Steve Prentice I use that snippet in my application but what about if we have a running process while we are backing our activity - the process is still running. How to fix that? If I use `android.os.Process.killProcess(android.os.Process.myPid());` but the animation between activities is not so smooth. Instead of this, it's flashing a black screen for about half of the second. – Stanimir Yakimov Jul 08 '14 at 12:43
  • 1
    @Stanimir Yakimov, look into android's services for running background processes. That'll make your life cycle management easier. If you're still unable to figure it out, I'd suggest creating a new question. – Steve Prentice Jul 08 '14 at 15:01
  • For `positive` button if you have imported onclicklistener already which is not the dialoginterface onclicklistener then use `new DialogInterface.OnClickListener(){` – Onimusha Nov 11 '15 at 01:53
  • For those who consider a `Toast` to be less intrusive, as I do, two good implementations are [here](http://stackoverflow.com/a/14006485/199364) and [here](http://stackoverflow.com/a/15728990/199364). – ToolmakerSteve Sep 22 '16 at 10:27
  • new DialogInterface.OnClickListener() you need to write this – Tabish khan Aug 30 '17 at 06:32
19

You don't need a counter for back presses.

Just store a reference to the toast that is shown:

private Toast backtoast;

Then,

public void onBackPressed() {
    if(USER_IS_GOING_TO_EXIT) {
        if(backtoast!=null&&backtoast.getView().getWindowToken()!=null) {
            finish();
        } else {
            backtoast = Toast.makeText(this, "Press back to exit", Toast.LENGTH_SHORT);
            backtoast.show();
        }
    } else {
        //other stuff...
        super.onBackPressed();
    }
}

This will call finish() if you press back while the toast is still visible, and only if the back press would result in exiting the application.

A Person
  • 1,350
  • 12
  • 23
  • instead of `this.finish()` rather call `NavUtils.navigateUpFromSameTask(this);` to get back to previous screen/ activity – To Kra Mar 30 '15 at 17:49
  • An alternative answer to consider [here](http://stackoverflow.com/a/14006485/199364). I haven't decided yet which approach I prefer. Some details of the linked answer could be added to this one, specifically the logic to cancel the toast as soon as the user exits. – ToolmakerSteve Sep 22 '16 at 10:23
14

I use this much simpler approach...

public class XYZ extends Activity {
    private long backPressedTime = 0;    // used by onBackPressed()


    @Override
    public void onBackPressed() {        // to prevent irritating accidental logouts
        long t = System.currentTimeMillis();
        if (t - backPressedTime > 2000) {    // 2 secs
            backPressedTime = t;
            Toast.makeText(this, "Press back again to logout",
                                Toast.LENGTH_SHORT).show();
        } else {    // this guy is serious
            // clean up
            super.onBackPressed();       // bye
        }
    }
}
SoloPilot
  • 1,484
  • 20
  • 17
  • Something strange happens on a Samsung Note tablet. Need to hit back several times fast. It doesn't like the 'backToast' approach either... – SoloPilot Feb 27 '14 at 19:39
  • Does it work better on Note if you cancel the toast before exiting? See [this](http://stackoverflow.com/a/14006485/199364) – ToolmakerSteve Sep 22 '16 at 10:30
2

Both your way and @Steve's way are acceptable ways to prevent accidental exits.

If choosing to continue with your implementation, you will need to make sure to have backpress initialized to 0, and probably implement a Timer of some sort to reset it back to 0 on keypress, after a cooldown period. (~5 seconds seems right)

yep
  • 94
  • 2
2

You may also need to reset counter in onPause to prevent cases when user presses home or navigates away by some other means after first back press. Otherwise, I don't see an issue.

Alex Gitelman
  • 24,429
  • 7
  • 52
  • 49
1

This is the best way, because if user not back more than two seconds then reset backpressed value.

declare one global variable.

 private boolean backPressToExit = false;

Override onBackPressed Method.

@Override
public void onBackPressed() {

    if (backPressToExit) {
        super.onBackPressed();
        return;
    }
    this.backPressToExit = true;
    Snackbar.make(findViewById(R.id.yourview), getString(R.string.exit_msg), Snackbar.LENGTH_SHORT).show();
    new Handler().postDelayed(new Runnable() {

        @Override
        public void run() {
            backPressToExit = false;
        }
    }, 2000);
}
Yogesh Rathi
  • 6,331
  • 4
  • 51
  • 81
  • declare one variable like as private boolean backPressToExit = false – Yogesh Rathi Sep 19 '15 at 16:20
  • 1) Please edit your answer to include the boolean you mention, rather than saying that in a comment. So people can see where the declaration should be. 2) Indeed this is an alternative way to be aware of time. Please explain why you consider this "best". Specifically, this has the overhead of creating a handler - what is gained by doing so? – ToolmakerSteve Sep 22 '16 at 10:18
1

If you want to exit your application from direct Second Activity without going to First Activity then try this code..`

In Second Activity put this code..

 @Override
public void onBackPressed() {
    new AlertDialog.Builder(this)
            .setTitle("Really Exit?")
            .setMessage("Are you sure you want to exit?")
            .setNegativeButton(android.R.string.no, null)
            .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {

                public void onClick(DialogInterface arg0, int arg1) {
                    setResult(RESULT_OK, new Intent().putExtra("EXIT", true));
                    finish();
                }

            }).create().show();
}

And Your First Activity Put this code.....

public class FirstActivity extends AppCompatActivity {

Button next;
private final static int EXIT_CODE = 100;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    next = (Button) findViewById(R.id.next);
    next.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View view) {

            startActivityForResult(new Intent(FirstActivity.this, SecondActivity.class), EXIT_CODE);
        }
    });
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == EXIT_CODE) {
        if (resultCode == RESULT_OK) {
            if (data.getBooleanExtra("EXIT", true)) {
                finish();
            }
        }
    }
}

}

Tabish khan
  • 772
  • 8
  • 11
0

additionally, you need to dissmis dialog before calling activity.super.onBackPressed(), otherwise you'll get "Activity has leaked.." error.

Example in my case with sweetalerdialog library:

 @Override
    public void onBackPressed() {
        //super.onBackPressed();
        SweetAlertDialog progressDialog = new SweetAlertDialog(this, SweetAlertDialog.WARNING_TYPE);
        progressDialog.setCancelable(false);
        progressDialog.setTitleText("Are you sure you want to exit?");
        progressDialog.setCancelText("No");
        progressDialog.setConfirmText("Yes");
        progressDialog.setCanceledOnTouchOutside(true);
        progressDialog.setConfirmClickListener(new SweetAlertDialog.OnSweetClickListener() {
            @Override
            public void onClick(SweetAlertDialog sweetAlertDialog) {
                sweetAlertDialog.dismiss();
                MainActivity.super.onBackPressed();
            }
        });
        progressDialog.show();
    }
kaMChy
  • 441
  • 5
  • 9
0

use to .onBackPressed() to back Activity specify

@Override
public void onBackPressed(){
    backpress = (backpress + 1);
    Toast.makeText(getApplicationContext(), " Press Back again to Exit ", Toast.LENGTH_SHORT).show();

    if (backpress>1) {
        this.finish();
    }
}
M.zar
  • 9
  • 2
0

I just had this issue and solved it by adding the following method:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
             // click on 'up' button in the action bar, handle it here
             return true;

        default:
            return super.onOptionsItemSelected(item);
    }
}    
marc
  • 223
  • 2
  • 6
0

You can also use onBackPressed by following ways using customized Toast:

enter image description here

customized_toast.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/txtMessage"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:drawableStart="@drawable/ic_white_exit_small"
    android:drawableLeft="@drawable/ic_white_exit_small"
    android:drawablePadding="8dp"
    android:paddingTop="8dp"
    android:paddingBottom="8dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:gravity="center"
    android:textColor="@android:color/white"
    android:textSize="16sp"
    android:text="Press BACK again to exit.."
    android:background="@drawable/curve_edittext"/>

MainActivity.java

@Override
public void onBackPressed() {

    if (doubleBackToExitPressedOnce) {
        android.os.Process.killProcess(Process.myPid());
        System.exit(1);
        return;
    }

    this.doubleBackToExitPressedOnce = true;
    Toast toast = new Toast(Dashboard.this);
    View view = getLayoutInflater().inflate(R.layout.toast_view,null);
    toast.setView(view);
    toast.setDuration(Toast.LENGTH_SHORT);
    int margin = getResources().getDimensionPixelSize(R.dimen.toast_vertical_margin);
    toast.setGravity(Gravity.BOTTOM | Gravity.CENTER_VERTICAL, 0, margin);
    toast.show();

    new Handler().postDelayed(new Runnable() {

        @Override
        public void run() {
            doubleBackToExitPressedOnce=false;
        }
    }, 2000);
}
Pankaj Lilan
  • 4,245
  • 1
  • 29
  • 48
0

Use this, it may help.

@Override
public void onBackPressed() {
    new AlertDialog.Builder(this)
            .setTitle("Message")
            .setMessage("Do you want to exit app?")
            .setNegativeButton("NO", null)
            .setPositiveButton("YES", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    UserLogin.super.onBackPressed();
                }
            }).create().show();
}
Manisa
  • 1
  • 1
0

implementing onBackPressed() by System time, if pressed twice within 2 sec, then will exit

public class MainActivity extends AppCompatActivity {
   private long backPressedTime;   // for back button timing less than 2 sec
   private Toast backToast;     // to hold message of exit
   @Override
public void onBackPressed() {


if (backPressedTime + 2000 > System.currentTimeMillis()) {

backToast.cancel();    // abruptly cancles the toast when pressed BACK Button *back2back*
super.onBackPressed();

} else {

backToast = Toast.makeText(getBaseContext(), "Press back again to exit", 
Toast.LENGTH_SHORT);
backToast.show();

}
backPressedTime = System.currentTimeMillis();

}

}