Android: modo corretto di utilizzare onBackPressed () con Toast


85

Ho scritto un pezzo di codice che darà all'utente un prompt chiedendo loro di premere di nuovo se vogliono uscire. Al momento il mio codice funziona in una certa misura, ma so che è scritto male e presumo che ci sia un modo migliore per farlo. Eventuali suggerimenti sarebbero utili!

Codice:

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

    if (backpress>1) {
        this.finish();
    }
}

5
Sostituisci this.finish()con super.onBackPressed();.
Fred

5
invece di this.finish()chiamare piuttosto NavUtils.navigateUpFromSameTask(this);per tornare alla schermata / attività precedente
To Kra

Risposte:


213

Vorrei implementare una finestra di dialogo chiedendo all'utente se desidera uscire e quindi chiamare super.onBackPressed()se lo hanno fatto.

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

Nell'esempio sopra, dovrai sostituire WelcomeActivity con il nome della tua attività.


funziona, ma nel mio caso il popup viene mostrato solo per pochi millisecondi e poi scompare e viene mostrata la nuova finestra. Non ho il tempo di fare clic su sì o no, e se eseguo il debug, non passa per il metodo onClick. Perché?
Accollativo

4
@Accollativo, sembra che tu abbia ancora una chiamata a super.onBackPressed()nella tua onBackPressed()definizione (diversa da quella all'interno del metodo onClick)?
Steve Prentice

6
Ogni app che ho visto predilige il metodo "second back press". Un utente che preme accidentalmente il tasto Indietro si infastidirà se viene visualizzata una finestra di dialogo. Il toast è meno invadente.
Karmic Coder

@ Steve Prentice Uso quello snippet nella mia applicazione, ma cosa succede se abbiamo un processo in esecuzione mentre supportiamo la nostra attività, il processo è ancora in esecuzione. Come risolverlo? Se uso android.os.Process.killProcess(android.os.Process.myPid());ma l'animazione tra le attività non è così fluida. Invece di questo, lampeggia una schermata nera per circa metà del secondo.
Stanimir Yakimov

1
@Stanimir Yakimov, esamina i servizi di Android per eseguire processi in background. Ciò semplificherà la gestione del ciclo di vita. Se non sei ancora in grado di capirlo, ti suggerisco di creare una nuova domanda.
Steve Prentice

19

Non hai bisogno di un contatore per i back press.

Memorizza semplicemente un riferimento al brindisi mostrato:

private Toast backtoast;

Poi,

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

Questo chiamerà finish()se premi Indietro mentre il brindisi è ancora visibile, e solo se la stampa indietro comporterebbe l'uscita dall'applicazione.


invece di this.finish()chiamare piuttosto NavUtils.navigateUpFromSameTask(this);per tornare alla schermata / attività precedente
To Kra

Una risposta alternativa da considerare qui . Non ho ancora deciso quale approccio preferire. A questa potrebbero essere aggiunti alcuni dettagli della risposta collegata, in particolare la logica per annullare il brindisi non appena l'utente esce.
ToolmakerSteve

14

Uso questo approccio molto più semplice ...

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

Succede qualcosa di strano su un tablet Samsung Note. Hai bisogno di rispondere più volte velocemente. Non gli piace nemmeno l'approccio 'backToast' ...
SoloPilot

Funziona meglio su Note se annulli il brindisi prima di uscire? Guarda questo
ToolmakerSteve

2

Sia la tua strada che quella di @Steve sono modi accettabili per prevenire uscite accidentali.

Se scegli di continuare con la tua implementazione, dovrai assicurarti di avere il backpress inizializzato su 0 e probabilmente implementare un Timerqualche tipo per resettarlo a 0 alla pressione dei tasti, dopo un periodo di cooldown. (~ 5 secondi sembrano giusti)


2

Potrebbe anche essere necessario reimpostare il contatore onPauseper evitare casi in cui l'utente preme a casa o si allontana con altri mezzi dopo la prima pressione indietro. Altrimenti, non vedo alcun problema.


1

Se vuoi uscire dalla tua applicazione dalla seconda attività diretta senza andare alla prima attività, prova questo codice ...

Nella seconda attività inserisci questo codice ..

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

E la tua prima attività Inserisci questo codice ...

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

}


1

Questo è il modo migliore, perché se l'utente non torna indietro di più di due secondi, ripristina il valore di contropressione.

dichiarare una variabile globale.

 private boolean backPressToExit = false;

onBackPressedMetodo di sostituzione .

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

dichiarare una variabile come come booleano privato backPressToExit = false
Yogesh Rathi

1) Modifica la tua risposta per includere il booleano che hai menzionato, piuttosto che dirlo in un commento. Così le persone possono vedere dove dovrebbe essere la dichiarazione. 2) In effetti questo è un modo alternativo per essere consapevoli del tempo. Spiega perché lo consideri "migliore". In particolare, questo ha il sovraccarico di creare un gestore: cosa si guadagna in questo modo?
ToolmakerSteve

0

inoltre, è necessario rimuovere la finestra di dialogo prima di chiamare activity.super.onBackPressed(), altrimenti verrà visualizzato l'errore "Activity has leaked ..".

Esempio nel mio caso con la libreria sweetalerdialog:

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

0

utilizzare per .onBackPressed () per sostenere l'attività specificata

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

    if (backpress>1) {
        this.finish();
    }
}

1
Spiega cosa hai aggiunto al codice originale e perché.
ToolmakerSteve

0

Ho appena avuto questo problema e l'ho risolto aggiungendo il seguente metodo:

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

0

Puoi anche utilizzare onBackPressed nei seguenti modi utilizzando Toast personalizzato:

inserisci qui la descrizione dell'immagine

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

0

Usa questo, potrebbe aiutare.

@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();
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.