242 votes

Sur Déconnexion, effacer la pile d’historique de l’activité, empêchant l’ouverture Activites connecté en-seule bouton « retour »

Toutes les activités dans mon application, un utilisateur d'être connecté pour voir. Les utilisateurs peuvent se connecter de n'importe quelle activité. C'est une exigence de l'application. À tout moment si l'utilisateur se connecte, je veux l'envoyer à l'utilisateur le Login Activity. À ce point, je veux que cette activité puisse être à la base de l'histoire de la pile, de sorte qu'en appuyant sur le bouton "retour" renvoie à l'utilisateur d'Android l'écran d'accueil.

J'ai vu cette question posée un peu d'endroits différents, tous ont répondu avec le même genre de réponses (que je décris ici), mais je veux la poser ici afin de recueillir les commentaires.

J'ai essayé d'ouvrir la Connexion de l'activité par l'établissement de ses Intent drapeaux FLAG_ACTIVITY_CLEAR_TOP qui semble faire comme il est indiqué dans la documentation, mais ne permet pas d'atteindre mon objectif de placer l'activité de Connexion au bas de l'histoire de la pile, et en empêchant l'utilisateur de naviguer de déjà-vu connecté activités. J'ai aussi essayé d'utiliser android:launchMode="singleTop" pour l'activité de Connexion dans le manifeste, mais ce n'est pas à atteindre mon but (et ne semble pas avoir d'effet de toute façon).

Je crois que j'ai besoin de l'histoire de la pile, ou de finir tous déjà ouvert des activités.

Une option est de demander à chaque activité, en onCreate vérifier enregistrés dans l'état, et finish() si n'est pas connecté. Je n'aime pas cette option, le bouton de retour seront toujours disponibles pour l'utilisation, la navigation de retour que les activités elles-mêmes.

L'option suivante est de maintenir l' LinkedList de références pour toutes les activités en cours qui est statiquement accessibles de partout (peut-être à l'aide de références faibles). Lors de la déconnexion, je vais accéder à cette liste et itérer sur tous déjà ouvert activités en invoquant finish() sur chacun d'eux. Je vais probablement commencer à mettre en œuvre cette méthode bientôt.

Je préfère utiliser quelques - Intent drapeau de la ruse pour ce faire, cependant. Je serais au-delà de la joie de constater que je peux réaliser mes conditions de l'application sans avoir à utiliser une des deux méthodes que j'ai décrites ci-dessus.

Est-il un moyen pour accomplir cela en utilisant Intent ou paramètres du manifeste, ou est mon deuxième option, le maintien d'un LinkedList a ouvert les activités de la meilleure option? Ou est-il une autre option que je suis complètement dominant?

216voto

Francesco Laurita Points 12027

Je peux vous proposer une autre approche IMHO plus robuste. Fondamentalement, vous devez diffuser un message de déconnexion à toutes vos activités doivent rester sous un statut connecté. Vous pouvez donc utiliser le sendBroadcast et installer un BroadcastReceiver dans toutes vos activités. Quelque chose comme ça:

 /** on your logout method:**/
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("com.package.ACTION_LOGOUT");
sendBroadcast(broadcastIntent);
 

Le récepteur (activité sécurisée):

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
/**snip **/
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("com.package.ACTION_LOGOUT");
    registerReceiver(new BroadcastReceiver() {

                    @Override
                    public void onReceive(Context context, Intent intent) {
                        Log.d("onReceive","Logout in progress");
    //At this point you should start the login activity and finish this one
                        finish();
                    }
                }, intentFilter);
//** snip **//
 

152voto

Mike Repass Points 2302

Il semble un rite de passage qu'un nouveau Androïde programmeur passe une journée à la recherche de cette question et la lecture de tous ces StackOverflow threads. Maintenant je suis nouvelle et je laisse ici de trace de mon humble expérience pour aider un futur pèlerin.

Tout d'abord, il n'est pas évident du tout ou de façon immédiate à ce faire par de mes recherches (en septembre 2012). Vous pensez que vous pourriez simple startActivity(new Intent(this, LoginActivity.class), CLEAR_STACK) mais non.

Vous POUVEZ faire startActivity(new Intent(this, LoginActivity.class)) avec FLAG_ACTIVITY_CLEAR_TOP - ce qui fera que le cadre de recherche en bas de la pile, de trouver votre antérieure instance d'origine de LoginActivity, recréer et effacer le reste de l' (à la hausse) de la pile. Et depuis la Connexion est sans doute au fond de la pile, vous avez maintenant une pile vide et le bouton de Retour juste quitte l'application.

MAIS cela ne fonctionne que si vous avez déjà quitté cette instance originale de LoginActivity vivant à la base de votre pile. Si, comme beaucoup de programmeurs, vous choisi de terminer() qui LoginActivity une fois que l'utilisateur s'est connecté avec succès, alors il n'est plus sur la base de la pile et de la FLAG_ACTIVITY_CLEAR_TOP sémantique ne s'appliquent pas ... vous finissez par la création d'une nouvelle LoginActivity sur le dessus de la pile existante. Ce qui est presque certainement PAS ce que vous voulez (comportement bizarre où l'utilisateur peut "retour" de leur moyen de sortir de la connecter à un écran précédent).

Donc, si vous avez déjà fini()'d la LoginActivity, vous avez besoin de poursuivre un mécanisme de compensation de la pile, puis le démarrage d'une nouvelle LoginActivity. Il semble que la réponse par @doreamon dans ce fil de discussion est la meilleure solution (au moins à mon humble yeux):

http://stackoverflow.com/a/9580057/614880

Je soupçonne fortement que la délicate implications de savoir si vous quittez LoginActivity vivant sont à l'origine de cette confusion.

Bonne Chance.

121voto

doraemon Points 4099

Supposons que LoginActivity -> HomeActivity -> ... -> SettingsActivity appelle signOut ():

    void signOut() {
        Intent intent = new Intent(this, HomeActivity.class);
        intent.putExtra("finish", true);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // To clean up all activities
        startActivity(intent);
        finish();
   }
 

AccueilActivité:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        boolean finish = getIntent().getBooleanExtra("finish", false);
        if (finish) {
            startActivity(new Intent(mContext, LoginActivity.class));
            finish();
            return;
        }
        initializeView();
    }
 

Cela fonctionne pour moi, j'espère que c'est utile pour vous aussi. :)

75voto

xbakesx Points 3419

Si vous utilisez API 11 ou une version ultérieure, vous pouvez essayer ceci: FLAG_ACTIVITY_CLEAR_TASK , il semble que vous résolvez exactement le problème que vous rencontrez. Évidemment, la foule pré-API 11 devrait utiliser une combinaison de toutes les activités de vérifier un @doreamon supplémentaire suggère ou une autre ruse.

(Aussi, pour ne pas l'utiliser, vous devez passer en FLAG_ACTIVITY_NEW_TASK )

     Intent intent = new Intent(this, LoginActivity.class);
    intent.putExtra("finish", true); // if you are checking for this in your other Activities
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | 
                    Intent.FLAG_ACTIVITY_CLEAR_TASK |
                    Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
    finish();
 

32voto

christinac Points 157

J'ai passé quelques heures sur ce trop ... et acceptez que FLAG_ACTIVITY_CLEAR_TOP sonne comme ce que vous voulez: effacer l'ensemble de la pile, sauf pour l'activité en cours de lancement, de sorte que le bouton de Retour quitte l'application. Pourtant, comme Mike Repass mentionné, FLAG_ACTIVITY_CLEAR_TOP ne fonctionne que lorsque l'activité de lancement est déjà dans la pile; lorsque l'activité n'est pas là, le drapeau ne pas faire n'importe quoi.

Que faire? Mettre l'activité en cours de lancement dans la pile avec FLAG_ACTIVITY_NEW_TASK, ce qui rend cette activité le début d'une nouvelle tâche sur l'histoire de la pile. Puis ajouter le FLAG_ACTIVITY_CLEAR_TOP drapeau.

Maintenant, quand FLAG_ACTIVITY_CLEAR_TOP va trouver une nouvelle activité dans la pile, il va être là et d'être tiré vers le haut avant que tout le reste est effacé.

Voici ma fonction de déconnexion; le paramètre View est la touche à laquelle la fonction est attachée.

public void onLogoutClick(final View view) {
    Intent i = new Intent(this, Splash.class);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    startActivity(i);
    finish();
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X