Search code examples
javaandroideclipsetoastback-button

Toast "Press back again to close" gives error when pressing back too often


My goal:

When a visitor goes back to the first page of my app, a toast appears to let the visitor know that he can press the back button again within 3 seconds to close the Android app.

Specific problem:

When you went back to the first page and the toast appears, the code works fine when you press back only once but when the toast appears and you press back more than one time, the following error message appears: "(appname) has stopped".

Does anyone know what causes this error message and how I can solve this?

MainActivity.java file:

// Open previous opened link from history on webview when back button pressed

private Boolean exit = false;
@Override
// Detect when the back button is pressed
public void onBackPressed() {
    if(webView.canGoBack()) {
        webView.goBack();
    }
    else {
        if (exit)
            this.finish();
        else {
            Toast.makeText(this, "Press again to exit.",
                Toast.LENGTH_SHORT).show();
                exit = true;
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        exit = false;
                    }
                }, 3 * 1000);
        }    

    }
}

Solution

  • It looks like when you fast-click the back button, it's calling this.finish() multiple times, resulting in the crash.

    You can do two things to prevent that. The first is to set the exit flag back to false after you call this.finish().

    In addition, to prevent a race-condition from multiple fast-clicks attempting to close the app, you can set a timestamp that will only allow one close event to be scheduled in each three second time window:

        private Boolean exit = false;
        private long timeStamp = 0;
        private Handler handler = new Handler();
        @Override
        // Detect when the back button is pressed
        public void onBackPressed() {
            if(webView.canGoBack()) {
                webView.goBack();
            }
            else {
                if (exit) {
                    exit = false; //added
                    this.finish();
                }
                else {
    
                    //added:
                    if (timeStamp == 0 || (System.currentTimeMillis() - timeStamp) > 3000) {
                        Toast.makeText(this, "Press again to exit.",
                            Toast.LENGTH_SHORT).show();
                        exit = true;
    
                        timeStamp = System.currentTimeMillis(); //added
    
                        handler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                exit = false;
                            }
                        }, 3 * 1000);
                    }
                }
    
            }
        }