Android - Comment remplacer le bouton «Retour» pour qu'il ne termine pas () mon activité?

199

J'ai actuellement une activité qui, lorsqu'elle sera affichée, une notification s'affichera également dans la barre de notification.

C'est ainsi que lorsque l'utilisateur appuie sur la maison et que l'activité est poussée à l'arrière-plan, il peut revenir à l'activité via la notification.

Le problème survient lorsqu'un utilisateur appuie sur le bouton de retour, mon activité est détruite mais la notification reste telle que je veux que l'utilisateur puisse appuyer mais toujours accéder à l'activité via la notification. Mais quand un UTILISATEUR essaie cela, je reçois des pointeurs Null car il essaie de démarrer une nouvelle activité plutôt que de ramener l'ancienne.

Donc, essentiellement, je veux que le bouton Retour agisse exactement de la même manière que le bouton Accueil et voici comment j'ai essayé jusqu'à présent:


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

Cependant, le code ci-dessus semble toujours permettre à mon activité d'être détruite, comment puis-je empêcher ma activité d'être détruite lorsque le bouton retour est enfoncé?

Donal Rafferty
la source
Il y a une question similaire: stackoverflow.com/questions/2459848/…
aleung
1
Réponse similaire .. stackoverflow.com/questions/5914040/…
Zar E Ahmer
Je pense aussi que vous devez changer votre code en `if (Integer.parseInt (android.os.Build.VERSION.SDK)> 5 , the <` devrait devenir un >.
SudoPlz
1
Même si vous résolvez cela, vous devez toujours gérer la possibilité que le système tue votre application, non? Je veux dire, le cas nul est toujours possible? Ou si le système tue votre application pour une raison quelconque, cela supprimera-t-il également votre notification? Je pense que cela doit être un problème, car le but d'une notification est d'exister même si l'application n'existe pas.
ToolmakerSteve
Vérifiez ici l'exemple de code d'application freakyjolly.com/how-to-add-back-arrow-in-android-activity
Code Spy

Réponses:

276

Retirez votre écouteur de clé ou revenez truequand vous en avez KEY_BACK.

Vous avez juste besoin de ce qui suit pour attraper la touche retour (assurez-vous de ne pas appeler super in onBackPressed()).

De plus, si vous prévoyez d'exécuter un service en arrière-plan, assurez-vous de regarder startForeground()et assurez-vous d'avoir une notification continue, sinon Android tuera votre service s'il a besoin de libérer de la mémoire.

@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
la source
70

Il était plus facile de l'implémenter avec une seule ligne de code:

@Override
public void onBackPressed() {
   moveTaskToBack(true);
}
Teo Inke
la source
Cela devrait être la réponse acceptée. Cela fait exactement ce que la question demande et utilise des fonctionnalités intégrées propres.
Shadoninja
Merci :) pouvez-vous élaborer le concept derrière cela?
Farrukh Faizy
1
Vous remplacez simplement l'événement onBackPressed (), ce qui fait déplacer l'activité vers l'arrière.
Squirrelkiller
1
Cette solution ne ramènera pas l'activité lorsque vous relancerez l'application à partir de l'écran d'accueil (s'il y a une autre activité sur la pile des tâches).
IgorGanapolsky
12

Je pense que ce que vous voulez, ce n'est pas de remplacer le bouton de retour (cela ne semble pas être une bonne idée - Android OS définit ce comportement, pourquoi le changer?), Mais d'utiliser le cycle de vie des activités et de conserver vos paramètres / données dans le Événement onSaveInstanceState (Bundle) .

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

Ensuite, vous utilisez onCreate (Bundle) pour tout retirer de ce bundle persistant et recréer votre état.

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

Considérez le pseudo-code ci-dessus pour vous orienter dans la bonne direction. La lecture du cycle de vie des activités devrait vous aider à déterminer la meilleure façon d'accomplir ce que vous recherchez.

kiswa
la source
Salut Kiswa, c'est vrai, je ne veux pas changer le comportement par défaut. J'ai essayé d'utiliser onSavedInstanceState et cela ne fonctionnait pas, mais je crois avoir repéré mon erreur maintenant. Merci
Donal Rafferty
5
J'ai rencontré au moins quelques situations où je voulais simuler le comportement standard de la pile d'activités sans réellement démarrer de nouvelles activités. Dans ces cas, je pense qu'il est approprié de remplacer le comportement onBackPressed () par défaut. En général, je suis d'accord: évitez de passer outre.
Matt Briançon
4
Je suis d'accord avec @Matt. Je travaille actuellement sur un jeu multiplateforme qui utilise le NDK. En tant que tel, c'est plus facile si tout est une seule activité. Pour cette raison, le comportement par défaut du bouton de retour consiste à échapper à l'application, ce qui n'est pas ce que la plupart des utilisateurs attendent. J'ai donc dû écraser le comportement par défaut pour que l'activité se comporte différemment, comme si l'utilisateur était effectivement passé à une autre activité et ne quitter l'application que dans certaines circonstances.
Leif Andersen
1
Le onSaveInstanceState et l'enregistrement des données ne sont-ils pas une question complètement différente?
Ted
@Ted -si vous dites qu'en plus de onSaveInstanceState, il doit également y avoir du code qui persiste les données des applications non UI, alors je suis d'accord. Dès que vous abandonnez le premier plan, votre application peut être supprimée sans autre avertissement. Doit toujours enregistrer tout ce qui compte. D'un autre côté, je pense que les méthodes de cycle de vie de l'application seront appelées quelle que soit la technique que vous utilisez pour masquer l'application mais la conserver, il ne devrait donc pas être nécessaire d'ajouter une logique de sauvegarde uniquement dans ce cas. Votre application a besoin de ce code aux bons endroits.
ToolmakerSteve
11

faites simplement cela ..

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

commentant le //super.onBackPressed (); fera l'affaire

androCoder-BD
la source
1
Une observation utile, mais cela ne fera-t-il pas que le bouton de retour ne fasse rien du tout, comme s'il était cassé? Ce n'est pas une bonne chose à faire - déroutant et ennuyeux pour les utilisateurs. L'IMHO doit ajouter la logique d'une autre réponse, pour agir comme le bouton d'accueil, comme cela a été demandé en question. La réponse acceptée mentionne qu'ils n'appelaient pas délibérément super méthode.
ToolmakerSteve
Oui tu as absolument raison. Il remplacera simplement le bouton de retour et ne fera rien jusqu'à ce que vous y mettiez un peu de logique. Peut être une condition pour appuyer deux fois sur le bouton pour fermer l'application ou vous voulez simplement désactiver une opération en cours (boîte de dialogue de progression), etc., mais c'est complètement à la hauteur de l'exigence.
androCoder-BD
5

Essaye ça:

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

Juste au cas où vous voudriez gérer le comportement du bouton de retour (en bas du téléphone) et du bouton d'accueil (celui à gauche de la barre d'action), cette activité personnalisée que j'utilise dans mon projet peut vous aider .

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

Exemple d'utilisation dans votre activité:

public class SomeActivity extends BackActivity {

    // ....

    @Override
    public void onBackPressed()
    {
        // Example of logic
        if ( yourConditionToOverride ) {
            // ... do your logic ...
        } else {
            super.onBackPressed();
        }
    }    
}
Ferran Maylinch
la source
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)
user3156040
la source
0

À Kotlin:

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

Pour plus d'informations, vous pouvez vérifier cela .

Il y a aussi une question spécifique sur le remplacement du bouton de retour dans Kotlin.

solaza
la source