web-dev-qa-db-fra.com

En cliquant deux fois sur le bouton Précédent pour quitter une activité

J'ai récemment remarqué ce phénomène dans de nombreuses applications et jeux Android: lorsque vous cliquez sur le bouton Précédent pour "quitter" l'application, un Toast affiche un message similaire à "Veuillez cliquer à nouveau sur RETOUR pour quitter".

Je me demandais, comme je le vois de plus en plus souvent, est-ce une fonctionnalité intégrée à laquelle vous pouvez en quelque sorte accéder dans une activité? J'ai examiné le code source de nombreuses classes mais je n'arrive pas à trouver quoi que ce soit à ce sujet.

Bien sûr, je peux penser à plusieurs façons de réaliser la même fonctionnalité assez facilement (le plus simple est probablement de garder un booléen dans l'activité qui indique si l'utilisateur a déjà cliqué une fois ...) mais je me demandais s'il y avait déjà quelque chose ici. .

EDIT: Comme l'a mentionné @LAS_VEGAS, je ne voulais pas vraiment dire "sortir" dans le sens traditionnel du terme. (c'est-à-dire terminé) je voulais dire "revenir à ce qui était ouvert avant le lancement de l'activité de démarrage de l'application", si cela a du sens :)

278
Guillaume

En activité Java:

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);
} 

Dans l'activité de Kotlin:

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)
    }

Je pense que ce gestionnaire aide à réinitialiser la variable après 2 secondes.

815
Sudheesh B Nair

Sudheesh B Nair a une réponse agréable (et acceptée) sur la question, qui, je pense, devrait avoir une meilleure alternative, telle que;

Qu'est-ce qui ne va pas avec le temps passé à mesurer et à vérifier si TIME_INTERVAL miliseconds (disons 2000) s'est écoulé depuis la dernière presse précédente? L'exemple de code suivant utilise System.currentTimeMillis(); pour stocker l'heure à laquelle onBackPressed() est appelée;

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();
}

Retour sur la réponse acceptée critique; Utiliser une flag pour indiquer si elle a été pressée dans le dernier TIME_INTERVAL (disons 2000) millisecondes et set-reset via la méthode Handler, la fonction postDelayed() a été la première chose à venir dans mon esprit. Mais l'action postDelayed() doit être annulée à la fermeture de l'activité, ce qui supprime la Runnable.

Afin de supprimer la Runnable, elle ne doit pas être déclarée anonyme, ni être déclarée en tant que membre avec la Handler aswell. Ensuite, la méthode removeCallbacks() de Handler peut être appelée de manière appropriée.

L’échantillon suivant est la démonstration;

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);
}

Merci à @NSouth pour sa contribution; Afin d'éviter que message toast apparaisse même après la fermeture de l'application, Toast peut être déclaré en tant que membre - disons mExitToast - et peut être annulé via mExitToast.cancel(); juste avant l'appel super.onBackPressed();.

197
Saro Taşciyan

Je pensais partager mon travail à la fin, je viens d’ajouter à mon activité:

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();
}

Et ça marche exactement comme je veux. Y compris la réinitialisation de l'état chaque fois que l'activité est reprise.

28
Guillaume

Diagramme de flux de processus: Press again to exit.

Code Java:

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;
}
24
vHow

Il y a moyen très simple parmi toutes ces réponses.

Écrivez simplement le code suivant dans la méthode onBackPressed().

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();
}

Vous devez définir l'objet back_pressed en tant que long dans l'activité.

18
Chintan Rathod

Sur la base de la réponse correcte et des suggestions formulées dans les commentaires, j'ai créé une démo qui fonctionne parfaitement et supprime les rappels du gestionnaire après son utilisation.

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);
        }
    }

}

J'espère que ça vous sera utile !!

12
Mehul Joisar

Ma solution en utilisant 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();
    }
}

Simple et stylé.

11
Hugo Passos
 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);

Déclarer une variable private boolean doubleBackToExitPressedOnce = false;

Collez ceci dans votre activité principale et cela résoudra votre problème.

10
Rakshith

Ce n’est pas une bonne idée d’utiliser un Runnable lorsqu’on quitte l’application, j’ai récemment trouvé un moyen beaucoup plus simple d’enregistrer et de comparer la période entre deux clics du bouton BACK. Exemple de code comme suit:

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();
}

Cela fera l'affaire pour quitter l'application en cliquant deux fois sur le bouton RETOUR dans un certain délai, soit 2000 millisecondes.

9
Max Lee

La réponse acceptée est Meilleure, mais si vous utilisez Android Design Support Library, vous pouvez utiliser SnackBar pour de meilleures vues. 

   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);
    }
6
Pratik Butani

Ce n'est pas une fonctionnalité intégrée. Je pense que ce n'est même pas le comportement recommandé. Les applications Android ne sont pas destinées à quitter:

Pourquoi les applications Android n'offrent-elles pas une option "Quitter"?

6
Caner
  1. Déclarez une variable globale Toast pour la classe MainActivity. exemple: Toast exitToast;
  2. Initialisez-le dans la méthode de vue onCreate. Exemple: exitToast = Toast.makeText (getApplicationContext (), "Appuyez de nouveau sur pour quitter", Toast.LENGTH_SHORT);
  3. Enfin, créez un onBackPressedMethod comme suit:

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

Cela fonctionne correctement, j'ai testé. et je pense que c'est beaucoup plus simple. 

6
Supto

Récemment, j'avais besoin de mettre en œuvre cette fonctionnalité de bouton de retour dans une de mes applications. Les réponses à la question initiale étaient utiles, mais je devais prendre en considération deux autres points:

  1. À certains moments, le bouton de retour est désactivé
  2. L’activité principale consiste à utiliser des fragments en combinaison avec une pile arrière

Sur la base des réponses et des commentaires, j'ai créé le code suivant:

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();
            }
        }
    }
}

Le code ci-dessus suppose que la bibliothèque de support est utilisée. Si vous utilisez des fragments mais pas la bibliothèque de support, vous souhaitez remplacer getSupportFragmentManager() par getFragmentManager().

Supprimez la première if, si le bouton Précédent n’est jamais annulé. Supprimez la seconde if, si vous n’utilisez pas de fragments ou une pile de retour de fragments

En outre, il est important de savoir que la méthode onBackPressed est prise en charge depuis Android 2.0. Vérifiez cette page pour une description détaillée. Pour que la fonction de presse arrière fonctionne également sur les versions antérieures, ajoutez la méthode suivante à votre activité:

@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
Tomasz Nguyen

Je sais que c’est une très vieille question, mais c’est la façon la plus simple de faire ce que vous voulez.

@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(); 
   }
}

Je sais que ce n'est pas la meilleure méthode, mais cela fonctionne bien!

4

Cela aide également lorsque l’activité de pile précédente est stockée dans la pile. 

J'ai modifié la réponse de Sudheesh 

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);
} 
3
Arpit Patel

Ici, j'ai généralisé écrire le code pour N comptes de prises. Le code est écrit de la même manière pour l'option Activer le développeur sur un téléphone portable Android. Même vous pouvez l'utiliser pour activer des fonctionnalités pendant que les développeurs testent l'application.

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

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

 }

Appeler askToExit () en option backpress ou logout.

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
Chintan Khetiya
@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);
}
2
Aditya_Android

A cette fin, j'ai implémenté la fonction suivante:

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();
}
2
Bu Ti

Lorsque HomeActivity contient le tiroir de navigation et la fonction double backPressed () pour quitter app . (N'oubliez pas de lancer la variable globale boolean doubleBackToExitPressedOnce = false;) Nouveau gestionnaire après 2 secondes, définissez la variable doubleBackPressedOnce sur 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);
        }
    }
}
2
Abhishek S

En 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);

    }
}

à 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)

        }
    }
2
Praveen

Voici le code de travail complet. Et n'oubliez pas de supprimer les rappels afin d'éviter toute fuite de mémoire dans l'application. :) 

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
Saket Kumar

J'ajouterais normalement un commentaire, mais ma réputation ne le permet pas ... Voici donc mes deux sous:

Dans Kotlin, vous pouvez utiliser des coroutines pour différer le réglage de la valeur false:

private var doubleBackPressed = false
private var toast : Toast ?= null

override fun onCreate(savedInstanceState: Bundle?) {
    toast = Toast.maketext(this, "Press back again to exit", Toast.LENGTH_SHORT)
}

override fun onBackPressed() {
    if (doubleBackPressed) {
        toast?.cancel()
        super.onBackPressed()
        return
    }
    this.doubleBackPressed = true
    toast?.show()
    GlobalScope.launch {
        delay(2000)
        doubleBackPressed = false
    }
}

Vous devrez importer:

import kotlinx.coroutines.launch
import kotlinx.coroutines.delay
import kotlinx.coroutines.GlobalScope
1
DannyRitiu

Quelques améliorations dans la réponse de Sudheesh B Nair, j'ai remarqué qu'il attendrait le gestionnaire même en appuyant deux fois immédiatement en arrière, donc annulez le gestionnaire comme indiqué ci-dessous. J'ai également annulé le pain grillé pour l'empêcher de s'afficher après la fermeture de l'application.

 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
Divyang Panchal

Dans cette situation, Snackbar est la meilleure option, puis Toast, pour afficher l'action de fermeture. Voici la méthode avec snack qui fonctionne.

@Override
        public void onBackPressed() {
            if (doubleBackToExitPressedOnce) {
                super.onBackPressed();
                return;
            }
            this.doubleBackToExitPressedOnce = true;
            Snackbar.make(this.getWindow().getDecorView().findViewById(Android.R.id.content), "Please click BACK again to exit", Snackbar.LENGTH_SHORT).show();

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

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

C'est la même chose pour la réponse acceptée et la plus votée, mais cette capture a utilisé Snackbar au lieu de Toast.

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
MobileOS

Pour l'activité qui a Navigation Drawer , utilisez le code suivant pour 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
Priya Rajan

Voici un autre moyen ... en utilisant la méthode CountDownTimer

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();
        }

    }
1
Anuj Sain
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
maniix

Une méthode légèrement meilleure que Zefnus je pense. Appelez System.currentTimeMillis () une seule fois et omettez 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();
    }
}
1
Khoa Chu Anh

Dans mon cas, je compte sur Snackbar#isShown() pour mieux 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
Kasim Rangwala

Dans Kotlin, à l'arrière, appuyez sur pour quitter l'application, vous pouvez utiliser:

Définir une variable globale:

private var doubleBackToExitPressedOnce = false

Remplacer onBackPressed:

override fun onBackPressed() {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed()
            return
        }

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

        Handler().postDelayed({
            doubleBackToExitPressedOnce = false;
        }, 2000)
    }
0
Shylendra Madda

Vous pouvez également utiliser la visibilité d'un pain grillé pour ne pas avoir besoin de cette solution Handler/postDelayed ultra.

Toast doubleBackButtonToast;

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

    doubleBackButtonToast = Toast.makeText(this, "Double tap back to exit.", Toast.LENGTH_SHORT);
}

@Override
public void onBackPressed() {
    if (doubleBackButtonToast.getView().isShown()) {
        super.onBackPressed();
    }

    doubleBackButtonToast.show();
}
0
Hudson Pereira

Retour lorsque le bouton est appuyé 2 fois 

public void click(View view){
    if (isBackActivated) {
        this.finish();
    }
    if (!isBackActivated) {
        isBackActivated = true;
        Toast.makeText(getApplicationContext(), "Again", Toast.LENGTH_SHORT).show();
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                isBackActivated = false;  // setting isBackActivated after 2 second
            }
        }, 2000);
    }

}
0
Ankush Shrivastava
private static final int TIME_INTERVAL = 2000;
private long mBackPressed;
    @Override
        public void onBackPressed() {

            if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis()) {
                super.onBackPressed();
                Intent intent = new Intent(FirstpageActivity.this,
                        HomepageActivity.class);
                startActivity(intent);
                finish();

                return;
            } else {

                Toast.makeText(getBaseContext(),
                        "Tap back button twice  to go Home.", Toast.LENGTH_SHORT)
                        .show();

                mBackPressed = System.currentTimeMillis();

            }

        }
0
Umesh Maharjan

Meilleure solution avec du pain grillé

En java

private Toast exitToast;

@Override
public void onBackPressed() {
    if (exitToast == null || exitToast.getView() == null || exitToast.getView().getWindowToken() == null) {
        exitToast = Toast.makeText(this, "Press again to exit", Toast.LENGTH_LONG);
        exitToast.show();
    } else {
        exitToast.cancel();
        super.onBackPressed();
    }
}

À Kotlin

private var exitToast: Toast? = null

override fun onBackPressed() {
    if (exitToast == null || exitToast!!.view == null || exitToast!!.view.windowToken == null) {
        exitToast = Toast.makeText(this, "Press again to exit", Toast.LENGTH_LONG)
        exitToast!!.show()
    } else {
        exitToast!!.cancel()
        super.onBackPressed()
    }
}
0
Karthik Kompelli

Voici mon point de vue sur ceci:

 int oddeven = 0;
 long backBtnPressed1;
 long backBtnPressed2;
 @Override
 public void onBackPressed() {
     oddeven++;
     if(oddeven%2==0){
         backBtnPressed2 = System.currentTimeMillis();
         if(backBtnPressed2-backBtnPressed1<2000) {
            super.onBackPressed();
            return;
         }
     }
     else if(oddeven%2==1) { 
         backBtnPressed1 = System.currentTimeMillis();    
        //  Insert toast back button here
     }
 }
0
R41N
 private static final int TIME_DELAY = 2000;
    private static long back_pressed;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    public void onBackPressed() {
        if (back_pressed + TIME_DELAY > System.currentTimeMillis()) {
            super.onBackPressed();
        } else {
            Toast.makeText(getBaseContext(), "Press once again to exit!",
                    Toast.LENGTH_SHORT).show();
        }
        back_pressed = System.currentTimeMillis();
    }
0
Avinash

Après avoir eu à mettre en œuvre plusieurs fois les mêmes choses, il a été décidé que quelqu'un créerait une bibliothèque simple à utiliser. Et c'est DoubleBackPress Android library . La README explique toutes les API fournies avec des exemples (comme ToastDisplay + Exit Activity ), mais décrit brièvement les étapes décrites ici.


Pour commencer, commencez par ajouter la dependency à votre application:

dependencies {
    implementation 'com.github.kaushikthedeveloper:double-back-press:0.0.1'
} 

Ensuite, créez un objet DoubleBackPress dans votre Activity qui fournit le comportement requis.

DoubleBackPress doubleBackPress = new DoubleBackPress();
doubleBackPress.setDoublePressDuration(3000);           // msec

Ensuite, créez une Toast qui doit être affichée sur le Premier Retour Appuyez sur. Ici, vous pouvez créer votre propre Toast ou aller avec Standard Toast fourni dans la library. Ce faisant ici par la dernière option.

FirstBackPressAction firstBackPressAction = new ToastDisplay().standard(this);
doubleBackPress.setFirstBackPressAction(firstBackPressAction);   // set the action

Maintenant, définissez ce qui doit se passer lorsque votre deuxième dos se produit. Ici, nous fermons l'activité.

DoubleBackPressAction doubleBackPressAction = new DoubleBackPressAction() {
    @Override
    public void actionCall() {
        finish();
        System.exit(0);
    }
};

Enfin, remplacez votre comportement de presse arrière par le comportement DoubleBackPress.

@Override
public void onBackPressed() {
    doubleBackPress.onBackPressed();
}

Exemple GIF d'exigences comportementales similaires

0
Kaushik NP

vous pouvez même le rendre plus simple, et sans utiliser un hander, faites seulement ceci =) 

Long firstClick = 1L;
Long secondClick = 0L;

@Override
public void onBackPressed() {
secondClick = System.currentTimeMillis();
    if ((secondClick - firstClick) / 1000 < 2) {
          super.onBackPressed();
    } else {
          firstClick = System.currentTimeMillis();
          Toast.makeText(MainActivity.this, "click BACK again to exit", Toast.LENGTH_SHORT).show();
        }
 }
0
G. Adnane

Voici un moyen de le faire en utilisant RxJava:

override fun onCreate(...) {
    backPresses.timeInterval(TimeUnit.MILLISECONDS, Schedulers.io())
            .skip(1) //Skip initial event; delay will be 0.
            .onMain()
            .subscribe {
                if (it.time() < 7000) super.onBackPressed() //7000 is the duration of a Toast with length LENGTH_LONG.
            }.addTo(compositeDisposable)

    backPresses.throttleFirst(7000, TimeUnit.MILLISECONDS, Schedulers.io())
            .subscribe { Toast.makeText(this, "Press back again to exit.", LENGTH_LONG).show() }
            .addTo(compositeDisposable)
}

override fun onBackPressed() = backPresses.onNext(Unit)
0
urgentx

Je pense que c'est ce dont vous avez besoin, je veux dire quand nous voulons montrer ce pain grillé, quand il n'y a qu'une seule activité dans la pile et que l'utilisateur appuie en arrière à partir de cette dernière activité de la pile.

var exitOpened=false // Declare it globaly

et dans la méthode onBackPressed, changez comme suit:

override fun onBackPressed() {
        if (isTaskRoot && !exitOpened)
        {
            exitOpened=true
            toast("Please press back again to exit")
            return
        }
        super.onBackPressed()
    }

Ici, isTaskRoot retournera true si l'activité en cours est l'activité racine (première activité) de la pile et false si ce n'est pas le cas.

Vous pouvez consulter la documentation officielle ici

0
Suraj Vaishnav