Android: ¿cómo anular el botón "Atrás" para que no termine () mi actividad?

199

Actualmente tengo una actividad que cuando se muestra una notificación también se mostrará en la barra de notificaciones.

Esto es para que cuando el Usuario presiona el botón de inicio y la Actividad es empujada a un segundo plano, puede volver a la Actividad a través de la Notificación.

El problema surge cuando un usuario presiona el botón de retroceso, mi actividad se destruye pero la notificación permanece, ya que quiero que el usuario pueda presionar hacia atrás pero aún pueda llegar a la actividad a través de la notificación. Pero cuando un USUARIO intenta esto, obtengo Punteros nulos porque intenta comenzar una nueva actividad en lugar de recuperar la anterior.

Así que esencialmente quiero que el botón Atrás actúe exactamente igual que el botón Inicio y así es como lo he intentado hasta ahora:


        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event)  {
            if (Integer.parseInt(android.os.Build.VERSION.SDK) < 5
                    && keyCode == KeyEvent.KEYCODE_BACK
                    && event.getRepeatCount() == 0) {
                Log.d("CDA", "onKeyDown Called");
                onBackPressed();
            }

            return super.onKeyDown(keyCode, event);
        }

        public void onBackPressed() {
            Log.d("CDA", "onBackPressed Called");
            Intent setIntent = new Intent(Intent.ACTION_MAIN);
            setIntent.addCategory(Intent.CATEGORY_HOME);
            setIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(setIntent); 

            return;
        }   

Sin embargo, el código anterior todavía parece permitir que se destruya mi Actividad. ¿Cómo puedo evitar que se destruya mi Actividad cuando se presiona el botón Atrás?

Donal Rafferty
fuente
Hay una pregunta similar: stackoverflow.com/questions/2459848/…
aleung
1
Respuesta similar ... stackoverflow.com/questions/5914040/…
Zar E Ahmer
También creo que debe cambiar su código a `if (Integer.parseInt (android.os.Build.VERSION.SDK)> 5 , the <` debería convertirse en a >.
SudoPlz
1
Incluso si resuelve esto, aún debe manejar la posibilidad de que el sistema elimine su aplicación, ¿verdad? Quiero decir, ¿el caso nulo todavía es posible? O si el sistema mata su aplicación por algún motivo, ¿eso también eliminará su notificación? Estoy pensando que esto debe ser un problema, ya que el propósito de una notificación es existir incluso si la aplicación no existe.
ToolmakerSteve
Consulte aquí el código de aplicación de ejemplo freakyjolly.com/how-to-add-back-arrow-in-android-activity
Code Spy el

Respuestas:

276

Elimine su oyente clave o regrese truecuando lo haya hecho KEY_BACK.

Solo necesita lo siguiente para capturar la tecla de retroceso (Asegúrese de no llamar a super in onBackPressed()).

Además, si planeas ejecutar un servicio en segundo plano, asegúrate de mirar startForeground()y asegurarte de tener una notificación continua o de lo contrario Android matará tu servicio si necesita liberar memoria.

@Override
public void onBackPressed() {
   Log.d("CDA", "onBackPressed Called");
   Intent setIntent = new Intent(Intent.ACTION_MAIN);
   setIntent.addCategory(Intent.CATEGORY_HOME);
   setIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
   startActivity(setIntent);
}
ekawas
fuente
70

Fue más fácil implementarlo solo con una línea de código:

@Override
public void onBackPressed() {
   moveTaskToBack(true);
}
Teo Inke
fuente
Esta debería ser la respuesta aceptada. Esto hace exactamente lo que hace la pregunta y está utilizando una funcionalidad integrada limpia.
Shadoninja el
Gracias :) ¿puedes elaborar el concepto detrás de esto?
Farrukh Faizy
1
Simplemente anule el evento onBackPressed (), haciendo que mueva la actividad hacia atrás.
Squirrelkiller
1
Esta solución no recuperará la actividad cuando reinicie la aplicación desde la pantalla de inicio (si hay otra actividad en la pila de tareas).
IgorGanapolsky
12

Creo que lo que quiere es no anular el botón de retroceso (eso no parece una buena idea, el sistema operativo Android define ese comportamiento, ¿por qué cambiarlo?), Sino usar el ciclo de vida de la actividad y mantener su configuración / datos en el evento onSaveInstanceState (Bundle) .

@Override
onSaveInstanceState(Bundle frozenState) {
    frozenState.putSerializable("object_key",
        someSerializableClassYouWantToPersist);
    // etc. until you have everything important stored in the bundle
}

Luego usa onCreate (Bundle) para sacar todo de ese paquete persistente y recrear su estado.

@Override
onCreate(Bundle savedInstanceState) {
    if(savedInstanceState!=null){ //It could be null if starting the app.
        mCustomObject = savedInstanceState.getSerializable("object_key");
    }
    // etc. until you have reloaded everything you stored
}

Considere el código psuedo anterior para señalarlo en la dirección correcta. Leer el Ciclo de vida de la actividad debería ayudarlo a determinar la mejor manera de lograr lo que está buscando.

kiswa
fuente
Hola Kiswa, esto es cierto, no quiero cambiar el comportamiento predeterminado. Intenté usar onSavedInstanceState y no funcionaba, pero creo que he detectado mi error ahora. Gracias
Donal Rafferty
55
Me he encontrado con al menos algunas situaciones en las que quería simular el comportamiento estándar de la pila de actividades sin realmente comenzar nuevas actividades. En estos casos, creo, es apropiado anular el comportamiento predeterminado de onBackPressed (). En general, sin embargo, estoy de acuerdo: evite anular.
Matt Briançon
44
Estoy de acuerdo con @Matt. Actualmente estoy trabajando en un juego multiplataforma que utiliza el NDK. Como tal, es más fácil si todo es una sola actividad. Debido a esto, el comportamiento predeterminado del botón Atrás es escapar de la aplicación, que no es lo que la mayoría de los usuarios esperan. Así que tuve que sobrescribir el comportamiento predeterminado para que la actividad se comportara de manera diferente, como si el usuario realmente hubiera ido a una actividad diferente, y solo saliera de la aplicación en ciertas circunstancias.
Leif Andersen
1
¿No es onSaveInstanceState y guardar datos una pregunta completamente diferente?
Ted
@Ted: si estás diciendo que además de onSaveInstanceState, también debe haber un código que conserve los datos de la aplicación que no son de UI, entonces estoy de acuerdo. Tan pronto como abandones el primer plano, tu aplicación podría ser eliminada sin más advertencia. Siempre debe guardar todo lo que importa. Por otro lado, creo que los métodos del ciclo de vida de la aplicación se llamarán independientemente de la técnica que use para ocultar la aplicación pero mantenerla, por lo que no debería ser necesario agregar una lógica de guardado solo para este caso. Sin embargo, su aplicación necesita ese código en todos los lugares correctos.
ToolmakerSteve
11

simplemente haz esto ...

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

comentando el //super.onBackPressed (); hará el truco

androCoder-BD
fuente
1
Una observación útil, pero ¿no hará esto que el botón Atrás no haga nada, como si estuviera roto? Eso no es algo bueno, confuso y molesto para los usuarios. En mi humilde opinión, debe agregar la lógica de otra respuesta, para actuar como botón de inicio, como se solicitó en la pregunta. La respuesta aceptada menciona que deliberadamente no estaban llamando al súper método.
ToolmakerSteve
Sí, tienes toda la razón. Simplemente anulará el botón Atrás y no hará nada hasta que coloque algo de lógica allí. Puede ser una condición para presionar dos veces el botón para cerrar la aplicación o simplemente desea deshabilitar una operación en curso (diálogo de progreso), etc., pero está completamente a la altura del requisito.
androCoder-BD
5

Prueba esto:

@Override
public void onBackPressed() {
    finish();
}
Thakur
fuente
3

En caso de que desee manejar el comportamiento del botón de retroceso (en la parte inferior del teléfono) y el botón de inicio (el que está a la izquierda de la barra de acción), esta actividad personalizada que estoy usando en mi proyecto puede ayudarlo .

import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;

/**
 * Activity where the home action bar button behaves like back by default
 */
public class BackActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setupHomeButton();
    }

    private void setupHomeButton() {
        final ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setHomeButtonEnabled(true);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                onMenuHomePressed();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    protected void onMenuHomePressed() {
        onBackPressed();
    }
}

Ejemplo de uso en su actividad:

public class SomeActivity extends BackActivity {

    // ....

    @Override
    public void onBackPressed()
    {
        // Example of logic
        if ( yourConditionToOverride ) {
            // ... do your logic ...
        } else {
            super.onBackPressed();
        }
    }    
}
Ferran Maylinch
fuente
1
@Override
public void onBackPressed() {
// Put your code here.
}

//I had to go back to the dashboard. Hence,

@Override
public void onBackPressed() {
    Intent intent = new Intent(this,Dashboard.class);
    startActivity(intent);
}
Just write this above or below the onCreate Method(within the class)
usuario3156040
fuente
0

En Kotlin:

val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
    // Handle the back button event
}

Para más información puedes consultar esto .

También hay una pregunta específica sobre cómo anular el botón de retroceso en Kotlin.

solaza
fuente