Klicken Sie zweimal auf die Schaltfläche "Zurück", um eine Aktivität zu beenden


329

Ich habe dieses Muster in letzter Zeit in vielen Android-Apps und -Spielen bemerkt: Wenn Sie auf die Schaltfläche "Zurück" klicken, um die Anwendung zu "beenden", a Toast zu beenden, wird eine Meldung angezeigt, die der Meldung "Zum Beenden erneut auf ZURÜCK klicken" ähnelt.

Ich habe mich gefragt, wie ich es immer öfter sehe, ob dies eine integrierte Funktion ist, auf die Sie in einer Aktivität irgendwie zugreifen können. Ich habe mir den Quellcode vieler Klassen angesehen, aber ich kann anscheinend nichts darüber finden.

Natürlich kann ich mir ein paar Möglichkeiten überlegen, um die gleiche Funktionalität ganz einfach zu erreichen (am einfachsten ist es wahrscheinlich, einen Booleschen Wert in der Aktivität beizubehalten, der angibt, ob der Benutzer bereits einmal geklickt hat ...), aber ich habe mich gefragt, ob hier bereits etwas vorhanden ist .

EDIT : Wie @LAS_VEGAS erwähnte, meinte ich nicht wirklich "Beenden" in der traditionellen Bedeutung. (dh beendet) Ich meinte "Zurück zu dem, was vor dem Start der Anwendungsstartaktivität geöffnet war", wenn das Sinn macht :)


[Android - App-Exit mit Toast bestätigen] [1]: stackoverflow.com/questions/14006461/…
resource8218

1
Ich hatte das gleiche Problem bei der Verwendung der HoloEverywhere-Bibliothek. Zu einfach können Sie Ihrer Aktivitätsdefinition in der Manifestdatei android: launchMode = "singleTask" hinzufügen.
Sohayb Hassoun


1
Mögliches Duplikat des zweimaligen
Klickens

Antworten:


947

In Java-Aktivität:

boolean doubleBackToExitPressedOnce = false;

@Override
public void onBackPressed() {
    if (doubleBackToExitPressedOnce) {
        super.onBackPressed();
        return;
    }

    this.doubleBackToExitPressedOnce = true;
    Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();

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

        @Override
        public void run() {
            doubleBackToExitPressedOnce=false;                       
        }
    }, 2000);
} 

In Kotlin Aktivität:

private var doubleBackToExitPressedOnce = false
override fun onBackPressed() {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed()
            return
        }

        this.doubleBackToExitPressedOnce = true
        Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show()

        Handler().postDelayed(Runnable { doubleBackToExitPressedOnce = false }, 2000)
    }

Ich denke, dieser Handler hilft, die Variable nach 2 Sekunden zurückzusetzen.


43
Beste Antwort! Sie können auch eine Bedingung hinzufügen, wenn (doubleBackToExitPressedOnce || fragmentManager.getBackStackEntryCount ()! = 0) {im Falle eines fragmentbasierten Hinzufügens
Anton Derevyanko

2
Ich stimme zu, dies ist definitiv die beste Antwort und sollte die akzeptierte Antwort sein.
BruceHill

3
Sie sollten die ausführbare Datei beim Beenden der Anwendung entfernen.
Wayne

Überprüfen Sie meine Antwort. Ich habe die Antwort von geändert Sudheesh B Nair, um die oben vorgeschlagenen Kommentare abzudecken.
Mehul Joisar

18
Es ist eine schöne schnelle Lösung / Antwort, aber ich stimme nicht zu, dass es die beste Lösung ist . Und für diejenigen, die denken, dass dies wieder die beste Antwort sein wird, kann ich nicht zustimmen. Diese Lösung verursacht Undichtigkeiten und erfordert zusätzlichen Aufwand für die Handhabung. Überprüfen Sie die Antworten unten für weitere Details.
Saro Taşciyan

226

Sudheesh B Nair hat eine nette (und akzeptierte) Antwort auf die Frage, die meiner Meinung nach eine bessere Alternative haben sollte, wie z.

Was ist falsch daran, die verstrichene Zeit zu messen und zu überprüfen, ob TIME_INTERVALseit dem letzten Zurückdrücken Millisekunden (z. B. 2000) vergangen sind ? Der folgende Beispielcode System.currentTimeMillis();zum Speichern der Uhrzeit onBackPressed()wird aufgerufen.

private static final int TIME_INTERVAL = 2000; // # milliseconds, desired time passed between two back presses.
private long mBackPressed;

@Override
public void onBackPressed()
{
    if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis()) 
    { 
        super.onBackPressed(); 
        return;
    }
    else { Toast.makeText(getBaseContext(), "Tap back button in order to exit", Toast.LENGTH_SHORT).show(); }

    mBackPressed = System.currentTimeMillis();
}

Zurück auf akzeptierte Antwort Kritik ; Verwendung einerflag um anzuzeigen , ob es in der letzten gedrückt wurde TIME_INTERVAL(etwa 2000) Millisekunden und Set - Reset ist über Handler‚s - postDelayed()Methode das erste , was in meinem Kopf zu kommen war. Die postDelayed()Aktion sollte jedoch abgebrochen werden, wenn die Aktivität geschlossen wirdRunnable .

Um das zu entfernen Runnable, darf es nicht anonym deklariert und zusammen mit dem Handleras auch als Mitglied deklariert werden. Dann removeCallbacks()Methode vonHandler kann die entsprechend aufgerufen werden.

Das folgende Beispiel ist die Demonstration;

private boolean doubleBackToExitPressedOnce;
private Handler mHandler = new Handler();

private final Runnable mRunnable = new Runnable() {
    @Override
    public void run() {
        doubleBackToExitPressedOnce = false;                       
    }
};

@Override 
protected void onDestroy() 
{ 
    super.onDestroy();

    if (mHandler != null) { mHandler.removeCallbacks(mRunnable); }
}

@Override
public void onBackPressed() {
    if (doubleBackToExitPressedOnce) {
        super.onBackPressed();
        return;
    }

    this.doubleBackToExitPressedOnce = true;
    Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();

    mHandler.postDelayed(mRunnable, 2000);
}

Vielen Dank an @NSouth für Ihren Beitrag. Um zu verhindern, dass Toastnachrichten auch nach dem Schließen der Anwendung angezeigt werden, Toastkönnen sie beispielsweise als Mitglied deklariert mExitToastund über mExitToast.cancel();kurz zuvor gekündigt werdensuper.onBackPressed(); Anruf .


9
Für diejenigen, die denken, dass es dasselbe ist, was Sudheesh B Nair gesagt hat: Gleiche Funktionalität, bessere Leistung. also +1.
BedirYilmaz

4
Ich mag diese Antwort und ich denke, es ist die beste. Ich meine, ich denke nicht, es ist die beste Antwort aus den oben genannten Gründen. Ich hoffe du bekommst mehr Upvotes für diesen. Ein Kommentar: Niemand findet es seltsam, dass der Toast ein paar Sekunden nach dem Schließen der App anhält? Niemand möchte den Toast absagen? Ich weiß, dass es ein kleines Detail sein kann, aber ich denke, dass das passieren sollte. Was denkt ihr?
Acrespo

1
@joonty danke für die Bearbeitung, das Schlüsselwort int fehlt seit einiger Zeit. Es wird jetzt kompiliert (:
Saro Taşciyan

2
@NSouth Der zweite Codeblock war ein Beispiel mit mHandlers, um zu zeigen, dass mehr Aufwand erforderlich ist. Ich schlage vor, Sie erwägen, den ersten Codeblock zu verwenden, der keinen Handler verwendet.
Saro Taşciyan

1
@acrespo Ich nehme an, wir haben eine solide Lösung für Toastnachrichten , die nach dem Schließen der Anwendung bestehen bleiben .
Saro Taşciyan

30

Ich dachte nur, ich würde erzählen, wie ich es am Ende gemacht habe, und habe gerade in meiner Aktivität hinzugefügt:

private boolean doubleBackToExitPressedOnce = false;

@Override
protected void onResume() {
    super.onResume();
    // .... other stuff in my onResume ....
    this.doubleBackToExitPressedOnce = false;
}

@Override
public void onBackPressed() {
    if (doubleBackToExitPressedOnce) {
        super.onBackPressed();
        return;
    }
    this.doubleBackToExitPressedOnce = true;
    Toast.makeText(this, R.string.exit_press_back_twice_message, Toast.LENGTH_SHORT).show();
}

Und es funktioniert genau so, wie ich es will. Einschließlich des Zurücksetzens des Status, wenn die Aktivität fortgesetzt wird.


15
Mit dieser Lösung können die beiden Rückpressen eine beliebige Zeitspanne zwischen sich haben. Sie können also Backeinmal drücken Backund eine Minute später erneut drücken, und die Anwendung wird beendet. Dies ist nicht das Verhalten, das der Benutzer erwarten wird.
BruceHill

1
Ich denke, es ist Geschmackssache. In diesem Fall benachrichtigen Sie den Benutzer nur einmal, damit der Benutzer weiß, dass er sich in der Hauptaktivität befindet, und ein erneutes Drücken der App beendet die App (wahrscheinlich nachdem der Benutzer einige Male zurückgedrückt hat, um zum Hauptbildschirm zurückzukehren). Wenn der Benutzer später erneut zurückdrückt, können wir annehmen, dass er die App beenden möchte (es sei denn, er hat in andere Aktivitäten navigiert und wahrscheinlich den Überblick darüber verloren, wie tief er geworden ist). In der oben akzeptierten Antwort denken Sie, dass der Benutzer möglicherweise vergisst, dass er sich bereits im Hauptbildschirm befindet. Beides ist in Ordnung, je nachdem, was Sie wollen oder in Betracht ziehen.
Ferran Maylinch

4
@ FerranMaylinch - Ich bin anderer Meinung. Dies ist nicht nur Geschmackssache. Wenn eine bedeutende Zeit vergangen ist, sollten wir davon ausgehen, dass der Benutzer in der Zwischenzeit andere Aktionen ausgeführt hat und nicht mehr berücksichtigt, was er zuvor getan hat, und sich dafür entschieden hat , die Bewerbung nicht fortzusetzen . In der Tat werden alle bis auf den außergewöhnlichsten Benutzer nicht einmal daran denken, dass er dies zuvor getan hat. Ohne zeitliche Begrenzung haben Sie die App in einem unsichtbaren Modus verlassen , über den der Benutzer nichts wissen kann. Ich halte das absolut für ein schlechtes Design der Benutzeroberfläche. Benutzer werden überrascht sein.
ToolmakerSteve

IMHO, bessere Varianten hier und hier .
ToolmakerSteve

26

Prozessablaufdiagramm: Zum Beenden erneut drücken.

Java Code:

private long lastPressedTime;
private static final int PERIOD = 2000;

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        switch (event.getAction()) {
        case KeyEvent.ACTION_DOWN:
            if (event.getDownTime() - lastPressedTime < PERIOD) {
                finish();
            } else {
                Toast.makeText(getApplicationContext(), "Press again to exit.",
                        Toast.LENGTH_SHORT).show();
                lastPressedTime = event.getEventTime();
            }
            return true;
        }
    }
    return false;
}

1
Ich habe dies ursprünglich als hilfreich abgestimmt. Das Problem ist, dass dies aus irgendeinem Grund bei einigen Mobilteilen nicht funktioniert. Die onBackPressed-Methode funktioniert am besten, aber dann haben Sie nicht die Zeitstempel, sodass Sie die Handler benötigen, wie in der akzeptierten Antwort angegeben.
Ravemir

23

Unter all diesen Antworten gibt es den einfachsten Weg.

Schreiben Sie einfach den folgenden Code in die onBackPressed()Methode.

long back_pressed;

@Override
public void onBackPressed() {
    if (back_pressed + 1000 > System.currentTimeMillis()){
        super.onBackPressed();
    }
    else{
        Toast.makeText(getBaseContext(),
                "Press once again to exit!", Toast.LENGTH_SHORT)
                .show();
    }
    back_pressed = System.currentTimeMillis();
}

Sie müssen das back_pressedObjekt wie longin der Aktivität definieren.


16

Meine Lösung mit Snackbar:

Snackbar mSnackbar;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final LinearLayout layout = findViewById(R.id.layout_main);
    mSnackbar = Snackbar.make(layout, R.string.press_back_again, Snackbar.LENGTH_SHORT);
}

@Override
public void onBackPressed() {
    if (mSnackbar.isShown()) {
        super.onBackPressed();
    } else {
        mSnackbar.show();
    }
}

Einfach und stilvoll.


2
Danke für diese Lösung. Einfach, effektiv, kein Risiko.
Ping Li

2
Out-of-Box-Lösung. (klatschen)
Hitesh Dhamshaniya

13

Basierend auf der richtigen Antwort und den Vorschlägen in den Kommentaren habe ich eine Demo erstellt, die absolut einwandfrei funktioniert und die Handler-Rückrufe nach der Verwendung entfernt.

MainActivity.java

package com.mehuljoisar.d_pressbacktwicetoexit;

import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.widget.Toast;

public class MainActivity extends Activity {

    private static final long delay = 2000L;
    private boolean mRecentlyBackPressed = false;
    private Handler mExitHandler = new Handler();
    private Runnable mExitRunnable = new Runnable() {

        @Override
        public void run() {
            mRecentlyBackPressed=false;   
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void onBackPressed() {

        //You may also add condition if (doubleBackToExitPressedOnce || fragmentManager.getBackStackEntryCount() != 0) // in case of Fragment-based add
        if (mRecentlyBackPressed) {
            mExitHandler.removeCallbacks(mExitRunnable);
            mExitHandler = null;
            super.onBackPressed();
        }
        else
        {
            mRecentlyBackPressed = true;
            Toast.makeText(this, "press again to exit", Toast.LENGTH_SHORT).show();
            mExitHandler.postDelayed(mExitRunnable, delay);
        }
    }

}

Ich hoffe es wird hilfreich sein !!


Sind Sie sicher, dass Sie den Handler entfernen, onBackPressed()um das Problem mit dem Speicherverlust zu beheben ?
Saro Taşciyan

@ Zefnus: Soweit ich weiß, wird es behoben. Korrigieren Sie mich, wenn ich falsch liege. Wie haben Sie Speicherprobleme mit dem obigen Code verfolgt?
Mehul Joisar

11
 public void onBackPressed() {
    if (doubleBackToExitPressedOnce) {
        super.onBackPressed();
        return;
    }

    this.doubleBackToExitPressedOnce = true;
    Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();

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

        @Override
        public void run() {
            doubleBackToExitPressedOnce=false;
        }
    }, 2000);

Variable deklarierenprivate boolean doubleBackToExitPressedOnce = false;

Fügen Sie dies in Ihre Hauptaktivität ein und dies wird Ihr Problem lösen


10

Es ist keine gute Idee, beim Beenden der Anwendung ein Runnable zu verwenden. Ich habe kürzlich eine viel einfachere Methode gefunden, um den Zeitraum zwischen zwei Klicks auf die Schaltfläche ZURÜCK aufzuzeichnen und zu vergleichen. Beispielcode wie folgt:

private static long back_pressed_time;
private static long PERIOD = 2000;

@Override
public void onBackPressed()
{
        if (back_pressed_time + PERIOD > System.currentTimeMillis()) super.onBackPressed();
        else Toast.makeText(getBaseContext(), "Press once again to exit!", Toast.LENGTH_SHORT).show();
        back_pressed_time = System.currentTimeMillis();
}

Dies reicht aus, um die Anwendung durch zweimaliges Klicken auf die Schaltfläche ZURÜCK innerhalb einer bestimmten Verzögerungszeit zu beenden, die im Beispiel 2000 Millisekunden beträgt.


8

Die akzeptierte Antwort ist die beste, aber wenn Sie sie verwenden Android Design Support Library, können Sie sie SnackBarfür bessere Ansichten verwenden.

   boolean doubleBackToExitPressedOnce = false;

    @Override
    public void onBackPressed() {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed();
            return;
        }

        this.doubleBackToExitPressedOnce = true;

        Snackbar.make(findViewById(R.id.photo_album_parent_view), "Please click BACK again to exit", Snackbar.LENGTH_SHORT).show();

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

            @Override
            public void run() {
                doubleBackToExitPressedOnce=false;
            }
        }, 2000);
    }

7

Es ist keine eingebaute Funktionalität. Ich denke, es ist nicht einmal das empfohlene Verhalten. Android-Apps sollen nicht beendet werden:

Warum bieten Android-Anwendungen keine "Beenden" -Option?


Punkt genommen. Mit Exit meinte ich "Zurück zum Startbildschirm"
Guillaume

3
Trotzdem ist es keine eingebaute Funktionalität. Ich kenne jedoch keine Richtlinie dagegen. Als Android-Benutzer mag ich solche Funktionen.
Caner

6
  1. Deklarieren Sie eine globale Toast-Variable für die MainActivity-Klasse. Beispiel: Toast exitToast;
  2. Initialisieren Sie es in der onCreate-Ansichtsmethode. Beispiel: exitToast = Toast.makeText (getApplicationContext (), "Zum Beenden erneut zurückdrücken", Toast.LENGTH_SHORT);
  3. Erstellen Sie abschließend eine onBackPressedMethod wie folgt:

    @Override
    public void onBackPressed() {
    
        if (exitToast.getView().isShown()) {
            exitToast.cancel();
            finish();
        } else {
            exitToast.show();
        }
    }

Das funktioniert richtig, ich habe getestet. und ich denke das ist viel einfacher.


5

Zefnus 'Antwort mit System.currentTimeMillis () ist die beste (+1). Die Art und Weise, wie ich es gemacht habe, ist nicht besser als das, aber ich poste es trotzdem, um die obigen Ideen zu ergänzen.

Wenn der Toast beim Drücken der Zurück-Taste nicht sichtbar ist, wird der Toast angezeigt. Wenn er sichtbar ist (der Rücken wurde bereits beim letzten Toast.LENGTH_SHORTMal einmal gedrückt ), wird er beendet.

exitToast = Toast.makeText(this, "Press again to exit", Toast.LENGTH_SHORT);
.
.
@Override
public void onBackPressed() {
   if (exitToast.getView().getWindowToken() == null) //if toast is currently not visible
      exitToast.show();  //then show toast saying 'press againt to exit'
   else {                                            //if toast is visible then
      finish();                                      //or super.onBackPressed();
      exitToast.cancel();
   }
}

1
Ist ein guter Weg, dies zu tun, aber wenn Sie mehr Toastnachrichten haben, ist dies nicht der Fall.
Boldijar Paul

@BoldijarPaul Nein, dieser Code überprüft nur den Status dieses bestimmten Toasts. Andere Toasts haben also keinen Einfluss auf das Verhalten.
Urgentx

5

Vor kurzem musste ich diese Funktion für die Zurück-Schaltfläche in einer meiner Apps implementieren. Die Antworten auf die ursprüngliche Frage waren nützlich, aber ich musste zwei weitere Punkte berücksichtigen:

  1. Zu bestimmten Zeitpunkten ist die Zurück-Taste deaktiviert
  2. Die Hauptaktivität besteht darin, Fragmente in Kombination mit einem Backstack zu verwenden

Basierend auf den Antworten und Kommentaren habe ich den folgenden Code erstellt:

private static final long BACK_PRESS_DELAY = 1000;

private boolean mBackPressCancelled = false;
private long mBackPressTimestamp;
private Toast mBackPressToast;

@Override
public void onBackPressed() {
    // Do nothing if the back button is disabled.
    if (!mBackPressCancelled) {
        // Pop fragment if the back stack is not empty.
        if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
            super.onBackPressed();
        } else {
            if (mBackPressToast != null) {
                mBackPressToast.cancel();
            }

            long currentTimestamp = System.currentTimeMillis();

            if (currentTimestamp < mBackPressTimestamp + BACK_PRESS_DELAY) {
                super.onBackPressed();
            } else {
                mBackPressTimestamp = currentTimestamp;

                mBackPressToast = Toast.makeText(this, getString(R.string.warning_exit), Toast.LENGTH_SHORT);
                mBackPressToast.show();
            }
        }
    }
}

Der obige Code setzt voraus, dass die Support-Bibliothek verwendet wird. Wenn Sie Fragmente verwenden , aber nicht die Unterstützung Bibliothek, möchten Sie ersetzen getSupportFragmentManager()durch getFragmentManager().

Entfernen Sie die erste if, wenn die Zurück-Taste nie abgebrochen wird. Entfernen Sie die zweite if, wenn Sie keine Fragmente oder einen Fragment-Back-Stack verwenden

Es ist auch wichtig zu wissen, dass die Methode onBackPressedseit Android 2.0 unterstützt wird. Auf dieser Seite finden Sie eine ausführliche Beschreibung. Fügen Sie Ihrer Aktivität die folgende Methode hinzu, damit die Funktion zum Zurückdrücken auch bei älteren Versionen funktioniert:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event)  {
    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ECLAIR
            && keyCode == KeyEvent.KEYCODE_BACK
            && event.getRepeatCount() == 0) {
        // Take care of calling this method on earlier versions of
        // the platform where it doesn't exist.
        onBackPressed();
    }

    return super.onKeyDown(keyCode, event);
}

5

In Java

private Boolean exit = false; 

if (exit) {
onBackPressed(); 
}

 @Override
public void onBackPressed() {
    if (exit) {
        finish(); // finish activity
    } else {
        Toast.makeText(this, "Press Back again to Exit.",
                Toast.LENGTH_SHORT).show();
        exit = true;
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                exit = false;
            }
        }, 3 * 1000);

    }
}

In Kotlin

 private var exit = false

 if (exit) {
        onBackPressed()
         }

 override fun onBackPressed(){
           if (exit){
               finish() // finish activity
           }else{
            Toast.makeText(this, "Press Back again to Exit.",
                    Toast.LENGTH_SHORT).show()
            exit = true
            Handler().postDelayed({ exit = false }, 3 * 1000)

        }
    }

4

Ich weiß, dass dies eine sehr alte Frage ist, aber dies ist der einfachste Weg, um das zu tun, was Sie wollen.

@Override
public void onBackPressed() {
   ++k; //initialise k when you first start your activity.
   if(k==1){
      //do whatever you want to do on first click for example:
      Toast.makeText(this, "Press back one more time to exit", Toast.LENGTH_LONG).show();
   }else{
      //do whatever you want to do on the click after the first for example:
      finish(); 
   }
}

Ich weiß, dass dies nicht die beste Methode ist, aber es funktioniert gut!


3
Dies ist nicht das allgemeine Verhalten des "zweimaligen Zurückklickens auf die Schaltfläche zum Beenden". Wie BruceHills Kommentar zu akzeptierten Antworten zeigt, behandelt Ihre Antwort auch kein
Zeitproblem

Aber damit können Sie zurückklicken, es wird die Nachricht angezeigt, und dann können Sie etwas länger warten, wieder zurückgehen und die App schließen, und das Verhalten des Double-Back-Timings wird nicht behandelt
Gastón Saillén

3

Zu diesem Zweck habe ich folgende Funktion implementiert:

private long onRecentBackPressedTime;
@Override
public void onBackPressed() {
    if (System.currentTimeMillis() - onRecentBackPressedTime > 2000) {
       onRecentBackPressedTime = System.currentTimeMillis();
       Toast.makeText(this, "Please press BACK again to exit", Toast.LENGTH_SHORT).show();
       return;
     }
   super.onBackPressed();
}

3

Dies ist auch hilfreich, wenn Sie zuvor Stapelaktivitäten im Stapel gespeichert haben.

Ich habe Sudheeshs Antwort geändert

boolean doubleBackToExitPressedOnce = false;

@Override
public void onBackPressed() {
    if (doubleBackToExitPressedOnce) {
        //super.onBackPressed();

  Intent intent = new Intent(Intent.ACTION_MAIN);
                    intent.addCategory(Intent.CATEGORY_HOME);
                    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);//***Change Here***
                    startActivity(intent);
                    finish();
                    System.exit(0);
        return;
    }

    this.doubleBackToExitPressedOnce = true;
    Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();

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

        @Override
        public void run() {
            doubleBackToExitPressedOnce=false;                       
        }
    }, 2000);
} 

2
@Override public void onBackPressed() {
   Log.d("CDA", "onBackPressed Called");
   Intent intent = new Intent();
   intent.setAction(Intent.ACTION_MAIN);
   intent.addCategory(Intent.CATEGORY_HOME);

   startActivity(intent);
}

1
Wie geht das überhaupt mit dem Double-Press-Szenario um? Sobald ich zurückschlage, wird eine Aktivität gestartet.
Kilokahn

2

Eine etwas bessere Methode als Zefnus, denke ich. Rufen Sie System.currentTimeMillis () nur einmal auf und lassen Sie Folgendes weg return;:

long previousTime;

@Override
public void onBackPressed()
{
    if (2000 + previousTime > (previousTime = System.currentTimeMillis())) 
    { 
        super.onBackPressed();
    } else {
        Toast.makeText(getBaseContext(), "Tap back button in order to exit", Toast.LENGTH_SHORT).show();
    }
}

2

Hier ist der vollständige Arbeitscode. Vergessen Sie auch nicht, die Rückrufe zu entfernen, damit in der App kein Speicherverlust auftritt. :) :)

private boolean backPressedOnce = false;
private Handler statusUpdateHandler;
private Runnable statusUpdateRunnable;

public void onBackPressed() {
        if (backPressedOnce) {
            finish();
        }

        backPressedOnce = true;
        final Toast toast = Toast.makeText(this, "Press again to exit", Toast.LENGTH_SHORT);
        toast.show();

        statusUpdateRunnable = new Runnable() {
            @Override
            public void run() {
                backPressedOnce = false;
                toast.cancel();  //Removes the toast after the exit.
            }
        };

        statusUpdateHandler.postDelayed(statusUpdateRunnable, 2000);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (statusUpdateHandler != null) {
        statusUpdateHandler.removeCallbacks(statusUpdateRunnable);
    }
}

2

Hier habe ich verallgemeinert den Code für N Tap Count geschrieben. Der Code ist ähnlich für die Option Entwickler aktivieren in Android-Gerät Telefon geschrieben. Sogar Sie können dies verwenden, um Funktionen zu aktivieren, während Entwickler die App testen.

 private Handler tapHandler;
 private Runnable tapRunnable;
 private int mTapCount = 0;
 private int milSecDealy = 2000;

onCreate(){
 ...
tapHandler = new Handler(Looper.getMainLooper());

 }

Rufen Sie askToExit () beim Zurückdrücken oder Abmelden auf.

private void askToExit() {
   if (mTapCount >= 2) {
    releaseTapValues();
    /* ========= Exit = TRUE  =========  */
   }

   mTapCount++;
   validateTapCount();
  }


  /* Check with null to avoid create multiple instances of the runnable */
  private void validateTapCount() {
   if (tapRunnable == null) {
    tapRunnable = new Runnable() {
     @Override
     public void run() {
      releaseTapValues();
      /* ========= Exit = FALSE  =========  */
     }
    };
    tapHandler.postDelayed(tapRunnable, milSecDealy);
   }
  }

  private void releaseTapValues() {
   /* Relase the value  */
   if (tapHandler != null) {
    tapHandler.removeCallbacks(tapRunnable);
    tapRunnable = null; /* release the object */
    mTapCount = 0; /* release the value */
   }
  }


  @Override
  protected void onDestroy() {
   super.onDestroy();
   releaseTapValues();
  }

2

ich benutze das

import android.app.Activity;
import android.support.annotation.StringRes;
import android.widget.Toast;

public class ExitApp {

    private static long lastClickTime;

    public static void now(Activity ctx, @StringRes int message) {
        now(ctx, ctx.getString(message), 2500);
    }

    public static void now(Activity ctx, @StringRes int message, long time) {
        now(ctx, ctx.getString(message), time);
    }

    public static void now(Activity ctx, String message, long time) {
        if (ctx != null && !message.isEmpty() && time != 0) {
            if (lastClickTime + time > System.currentTimeMillis()) {
                ctx.finish();
            } else {
                Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show();
                lastClickTime = System.currentTimeMillis();
            }
        }
    }

}

Verwenden Sie im EreignisonBackPressed

@Override
public void onBackPressed() {
   ExitApp.now(this,"Press again for close");
}

oder ExitApp.now(this,R.string.double_back_pressed)

Für Änderungssekunden sind geschlossene, angegebene Millisekunden erforderlich

ExitApp.now(this,R.string.double_back_pressed,5000)


2

Wenn HomeActivity eine Navigationsleiste und eine doppelte backPressed () -Funktion enthält, um die App zu beenden. (Vergessen Sie nicht, die globale Variable boolean doubleBackToExitPressedOnce = false zu initialisieren.) Neuer Handler nach 2 Sekunden setzen Sie die Variable doubleBackPressedOnce auf false

@Override
public void onBackPressed() {
    DrawerLayout drawer = findViewById(R.id.drawer_layout);
    if (drawer.isDrawerOpen(GravityCompat.END)) {
        drawer.closeDrawer(GravityCompat.END);
    } else {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed();
            moveTaskToBack(true);
            return;
        } else {
            this.doubleBackToExitPressedOnce = true;
            Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    doubleBackToExitPressedOnce = false;
                }
            }, 2000);
        }
    }
}

1
boolean doubleBackToExitPressedOnce = false;

@Override
public void onBackPressed() {
    if (doubleBackToExitPressedOnce) {
        super.onBackPressed();
        return;
    }

    this.doubleBackToExitPressedOnce = true;

    Snackbar.make(findViewById(R.id.photo_album_parent_view), "Please click BACK again to exit", Snackbar.LENGTH_SHORT).show();

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

        @Override
        public void run() {
            doubleBackToExitPressedOnce=false;
        }
    }, 2000);
}

1

Einige Verbesserungen in der Antwort von Sudheesh B Nair, ich habe bemerkt, dass es auf den Handler wartet, auch wenn es zweimal zweimal zurückgedrückt wird. Brechen Sie den Handler also ab, wie unten gezeigt. Ich habe Toast auch abgebrochen, um zu verhindern, dass er nach dem Beenden der App angezeigt wird.

 boolean doubleBackToExitPressedOnce = false;
        Handler myHandler;
        Runnable myRunnable;
        Toast myToast;

    @Override
        public void onBackPressed() {
            if (doubleBackToExitPressedOnce) {
                myHandler.removeCallbacks(myRunnable);
                myToast.cancel();
                super.onBackPressed();
                return;
            }

            this.doubleBackToExitPressedOnce = true;
            myToast = Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT);
            myToast.show();

            myHandler = new Handler();

            myRunnable = new Runnable() {

                @Override
                public void run() {
                    doubleBackToExitPressedOnce = false;
                }
            };
            myHandler.postDelayed(myRunnable, 2000);
        }

1

Dies ist das Gleiche wie die akzeptierte und am meisten gewählte Antwort, aber diese abgeschnittene Snackbar wurde anstelle von Toast verwendet.

boolean doubleBackToExitPressedOnce = false;

    @Override
    public void onBackPressed() {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed();
            return;
        }

        this.doubleBackToExitPressedOnce = true;
        Snackbar.make(content, "Please click BACK again to exit", Snackbar.LENGTH_SHORT)
                .setAction("Action", null).show();


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

            @Override
            public void run() {
                doubleBackToExitPressedOnce=false;
            }
        }, 2000);
    }

1

In meinem Fall bin ich Snackbar#isShown()zum Besseren darauf angewiesen UX.

private Snackbar exitSnackBar;

@Override
public void onBackPressed() {
    if (isNavDrawerOpen()) {
        closeNavDrawer();
    } else if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
        if (exitSnackBar != null && exitSnackBar.isShown()) {
            super.onBackPressed();
        } else {
            exitSnackBar = Snackbar.make(
                    binding.getRoot(),
                    R.string.navigation_exit,
                    2000
            );
            exitSnackBar.show();
        }
    } else {
        super.onBackPressed();
    }
}

1

Verwenden Sie für die Aktivität mit Navigationsleiste den folgenden Code für OnBackPressed ()

boolean doubleBackToExitPressedOnce = false;

@Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            if (doubleBackToExitPressedOnce) {
                if (getFragmentManager().getBackStackEntryCount() ==0) {
                    finishAffinity();
                    System.exit(0);
                } else {
                    getFragmentManager().popBackStackImmediate();
                }
                return;
            }

            if (getFragmentManager().getBackStackEntryCount() ==0) {
                this.doubleBackToExitPressedOnce = true;
                Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();

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

                    @Override
                    public void run() {
                        doubleBackToExitPressedOnce = false;
                    }
                }, 2000);
            } else {
                getFragmentManager().popBackStackImmediate();
            }
        }
    }

1

Hier ist ein anderer Weg ... mit der CountDownTimer- Methode

private boolean exit = false;
@Override
public void onBackPressed() {
        if (exit) {
            finish();
        } else {
            Toast.makeText(this, "Press back again to exit",
                    Toast.LENGTH_SHORT).show();
            exit = true;
            new CountDownTimer(3000,1000) {

                @Override
                public void onTick(long l) {

                }

                @Override
                public void onFinish() {
                    exit = false;
                }
            }.start();
        }

    }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.