Android: forma correcta de usar onBackPressed () con Toast

85

Escribí un fragmento de código que le dará al usuario un mensaje pidiéndole que vuelva a presionar si desea salir. Actualmente tengo mi código funcionando hasta cierto punto, pero sé que está mal escrito y supongo que hay una mejor manera de hacerlo. ¡Cualquier sugerencia sería útil!

Código:

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

    if (backpress>1) {
        this.finish();
    }
}
Mella
fuente
5
Reemplazar this.finish()con super.onBackPressed();.
Fred
5
en lugar de this.finish()llamar NavUtils.navigateUpFromSameTask(this);para volver a la pantalla / actividad anterior
A Kra

Respuestas:

213

Implementaría un diálogo preguntando al usuario si quería salir y luego llamaría super.onBackPressed()si lo hiciera.

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

En el ejemplo anterior, deberá reemplazar WelcomeActivity con el nombre de su actividad.

Steve Prentice
fuente
esto funciona, pero en mi caso, la ventana emergente se muestra solo por unos pocos milisegundos y luego desaparece y se muestra la nueva ventana. No tengo tiempo para hacer clic en sí o no, y si lo depuro, no pasa por el método onClick. ¿Por qué?
Accollativo
4
@Accollativo, ¿parece que todavía tienes una llamada a super.onBackPressed()en tu onBackPressed()definición (que no sea la que está dentro del método onClick)?
Steve Prentice
6
Todas las aplicaciones que he visto favorecen el método de "segunda pulsación hacia atrás". Un usuario que accidentalmente presione la tecla Atrás se molestará si aparece un cuadro de diálogo. El brindis es menos intrusivo.
Codificador kármico
@Steve Prentice Utilizo ese fragmento en mi aplicación, pero ¿qué pasa si tenemos un proceso en ejecución mientras respaldamos nuestra actividad? El proceso aún se está ejecutando. ¿Cómo arreglar eso? Si lo uso android.os.Process.killProcess(android.os.Process.myPid());pero la animación entre actividades no es tan fluida. En lugar de esto, muestra una pantalla negra durante aproximadamente la mitad del segundo.
Stanimir Yakimov
1
@Stanimir Yakimov, busque en los servicios de Android para ejecutar procesos en segundo plano. Eso facilitará la gestión del ciclo de vida. Si aún no puede resolverlo, le sugiero que cree una nueva pregunta.
Steve Prentice
19

No necesitas un contador para prensas traseras.

Simplemente guarde una referencia al brindis que se muestra:

private Toast backtoast;

Entonces,

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

Esto llamará finish()si presiona hacia atrás mientras el brindis aún está visible, y solo si al presionar hacia atrás se sale de la aplicación.

Siidheesh
fuente
en lugar de this.finish()llamar NavUtils.navigateUpFromSameTask(this);para volver a la pantalla / actividad anterior
A Kra
Una respuesta alternativa para considerar aquí . Aún no he decidido qué enfoque prefiero. A esta se podrían agregar algunos detalles de la respuesta vinculada, específicamente la lógica para cancelar el brindis tan pronto como el usuario salga.
ToolmakerSteve
14

Utilizo este enfoque mucho más simple ...

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
fuente
Algo extraño sucede en una tableta Samsung Note. Necesito devolver el golpe varias veces rápido. Tampoco le gusta el enfoque de 'backToast' ...
SoloPilot
¿Funciona mejor en Note si cancela el brindis antes de salir? Vea esto
ToolmakerSteve
2

Tanto a tu manera como a la de @ Steve son formas aceptables de evitar salidas accidentales.

Si elige continuar con su implementación, deberá asegurarse de tener la retropresión inicializada en 0, y probablemente implementar una Timerde algún tipo para restablecerla a 0 al presionar la tecla, después de un período de enfriamiento. (~ 5 segundos parece correcto)


fuente
2

También es posible que deba restablecer el contador onPausepara evitar casos en los que el usuario presiona Inicio o se aleja por algún otro medio después de presionar por primera vez. De lo contrario, no veo ningún problema.

Alex Gitelman
fuente
1

Si desea salir de su aplicación desde la segunda actividad directa sin ir a la primera actividad, pruebe este código ...`

En Segunda Actividad ponga este código.

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

Y tu primera actividad Pon este código .....

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
fuente
1

Esta es la mejor manera, porque si el usuario no retrocede más de dos segundos, restablezca el valor de retroceso.

declarar una variable global.

 private boolean backPressToExit = false;

onBackPressedMétodo de anulación .

@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
fuente
declarar una variable como booleana privada backPressToSalir = falso
Yogesh Rathi
1) Edite su respuesta para incluir el booleano que menciona, en lugar de decirlo en un comentario. Para que la gente pueda ver dónde debería estar la declaración. 2) De hecho, esta es una forma alternativa de ser consciente del tiempo. Explique por qué considera esto "mejor". Específicamente, esto tiene la sobrecarga de crear un controlador: ¿qué se gana al hacerlo?
ToolmakerSteve
0

Además, debe descartar el cuadro de diálogo antes de llamar activity.super.onBackPressed(), de lo contrario obtendrá el error "La actividad se ha filtrado ...".

Ejemplo en mi caso con la biblioteca 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();
    }
kaMChy
fuente
0

usar para .onBackPressed () para retroceder Especificar actividad

@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
fuente
1
Explique lo que ha agregado al código original y por qué.
ToolmakerSteve
0

Acabo de tener este problema y lo resolví agregando el siguiente método:

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

También puede usar onBackPressed de las siguientes formas usando Toast personalizado:

ingrese la descripción de la imagen aquí

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);
}
Pankaj Lilan
fuente
0

Use esto, puede ayudar.

@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
fuente