Comment vérifier si une activité est la dernière de la pile d'activités d'une application?

Réponses:

116

MISE À JOUR (juillet 2015):

Depuis getRunningTasks () se dépréciée, de l' API 21 , il est préférable de suivre raukodraug réponse ou Ed Burnette un (je préférerais la deuxième).


Il est possible de vérifier les tâches en cours et leur pile en utilisant ActivityManager .

Donc, pour déterminer si une activité est la dernière:

  • demandez les autorisations android.permission.GET_TASKS dans le manifeste.
  • Utilisez le code suivant:

    ActivityManager mngr = (ActivityManager) getSystemService( ACTIVITY_SERVICE );
    
    List<ActivityManager.RunningTaskInfo> taskList = mngr.getRunningTasks(10);
    
    if(taskList.get(0).numActivities == 1 &&
       taskList.get(0).topActivity.getClassName().equals(this.getClass().getName())) {
        Log.i(TAG, "This is last activity in the stack");
    }
    

Veuillez noter que le code ci-dessus ne sera valide que si vous avez une seule tâche. S'il est possible que ce nombre de tâches existe pour votre application, vous devrez vérifier d'autres éléments de la liste des tâches . En savoir plus sur les tâches Tâches et Back Stack


sandrstar
la source
25
H9kDroid a fait une suggestion correcte. La réponse choisie est un hack. On devrait le faire de la bonne façon en utilisant la isTaskRoot()méthode.
Sufian
@Sufian où est-il particulièrement piraté? Le code est logique et utilise des API Android ouvertes de la manière dont elles ont l'intention d'être utilisées (par exemple, getRunningTasks devrait être utilisé pour exécuter des tâches et on pourrait vouloir l'appeler uniquement dans le but d'analyser ces tâches). L'utilisation de get (0) est bien documentée et logique 'Renvoie une liste des tâches en cours d'exécution, la plus récente étant la première et les plus anciennes après dans l'ordre'.
sandrstar
2
getRunningTasks () est obsolète au niveau de l'API 21.
gilchris
Puis-je faire la même chose pour les fragments. Si oui, comment? S'il vous plaît aider
Sagar Devanga
1
@ Mr.Drew voir la réponse la plus élevée de @ raukodraug
David Wasser
167

Je vais publier le commentaire de @ H9kDroid comme la meilleure réponse ici pour les personnes qui ont une question similaire.

Vous pouvez utiliser isTaskRoot () pour savoir si l'activité est la racine d'une tâche.

J'espère que ça aide

raukodraug
la source
1
pouvez-vous s'il vous plaît fournir la seule ligne de code afin que son clair sur la façon d'utiliser isTaskRoot. Merci.
Kaveesh Kanwal
18
@TheHunterif (isTaskRoot()) { // do something }
howettl
3
Le seul problème est que sur <= 4.4, je le vois faire un comportement différent de celui de> = 5.x. Il semble toujours retourner faux.
chubbsondubs
Je pense que vous devriez envisager d'incorporer l'exemple de code fourni dans les commentaires dans la réponse, pour le rendre plus facile pour les futurs lecteurs.
Isac
excellente réponse. dans mon cas, après que l'utilisateur clique sur une notification, l'activité peut être la racine s'il a fermé l'application avant
dave o grady
19

J'espère que cela aidera les nouveaux débutants.Sur la base des réponses ci-dessus qui fonctionnent bien pour moi, je partage également un extrait de code afin qu'il soit facile à mettre en œuvre.

solution: j'ai utilisé isTaskRoot()qui renvoie true si l'activité actuelle est uniquement une activité dans votre pile et autre que je gère également le cas dans lequel si j'ai une activité dans la pile, allez à la dernière activité de la pile au lieu d'en ouvrir une nouvelle personnalisée.

Dans votre activité

   @Override
    public void onBackPressed() {

        if(isTaskRoot()){
            startActivity(new Intent(currentActivityName.this,ActivityNameYouWantToOpen.class));
            // using finish() is optional, use it if you do not want to keep currentActivity in stack
            finish();
        }else{
            super.onBackPressed();
        }

    }
Abhishek Garg
la source
16

il existe une solution plus simple à cela, vous pouvez utiliser isTaskRoot () dans votre activité

Laxmikant Revdikar
la source
5

Bien qu'il puisse y avoir un moyen d'y parvenir (voir les autres réponses), je suggérerais que vous ne devriez pas le faire. Les applications Android normales ne devraient pas avoir besoin de savoir si l'écran d'accueil est sur le point de s'afficher ou non.

Si vous essayez d'enregistrer des données, placez le code d'enregistrement des données dans votre méthode onPause (). Si vous essayez de donner à l'utilisateur un moyen de changer d'avis sur l'application existante, vous pouvez intercepter la touche haut / bas pour la touche Retour et la méthode onBackPressed () et leur présenter un "Êtes-vous sûr?" rapide.

Ed Burnette
la source
1
Et si j'ai besoin d'un service en cours d'exécution tant que l'utilisateur n'a pas quitté l'activité? Je ne peux piéger aucune des fonctions telles que onStop car elles pourraient être appelées après la désactivation de l'écran.
Michael
2
Si un service d'arrière-plan lance une activité, vous aimeriez peut-être savoir si c'est la seule activité de la pile.
Matt W
4

Une façon de garder une trace de cela est d'inclure un marqueur lorsque vous démarrez une nouvelle activité et de vérifier si le marqueur existe.

Chaque fois que vous démarrez une nouvelle activité, insérez le marqueur:

newIntent=new Intent(this, NextOne.class);
newIntent.putExtra(this.getPackageName()+"myself", 0);
startActivity(newIntent);

Et vous pouvez ensuite le vérifier comme ceci:

boolean islast=!getIntent().hasExtra(this.getPackageName()+"myself")
H9kDroid
la source
1
Ne fonctionne pas si l'activité est tuée et la pile d'activités est reconstruite - chaque activité à la demande.
AlikElzin-kilaka
3

Le problème avec la solution de sandrstar est le suivant ActivityManager: vous avez besoin d'une autorisation pour obtenir les tâches de cette façon. J'ai trouvé un meilleur moyen:

getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)

Le Activitybas de la pile devrait toujours obtenir cette catégorie par défaut, tandis que les autres activités ne devraient pas l'obtenir.
Mais même si cela échoue sur certains appareils, vous pouvez le configurer lors du démarrage de votre Activity:

Intent intent = new Intent(startingActivity, SomeActivityClass.class);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
activity.startActivity(intent);
A. Binzxxxxxx
la source
Que faire si l'activité est ouverte à partir de la notification push? Ils n'ont pas le lancement de la catégorie
nbtk
Je suis convaincu que la deuxième partie de ma réponse s'applique toujours. Vous pouvez définir la catégorie comme un indice dans l'intention. Dans ce cas, peut-être dans l'intention de votre contexte de notification. En dehors de cela, vous pouvez également utiliser des indicateurs pour cela. voir ce lien pour une création de notification avec intention: stackoverflow.com/questions/13716723/…
A. Binzxxxxxx
Néanmoins, si votre activité la plus ancienne est MainActivity et qu'elle est maintenant reprise, puis que vous recevez une notification push et que vous configurez pendingIntent pour s'ouvrir avec CATEGORY_LAUNCHER, alors vous aurez 2 activités avec cette catégorie. Probablement sur différentes tâches cependant
nbtk
Je ne sais pas exactement comment cela fonctionne avec les notifications. Je ne les ai jamais utilisés comme vous le faites ici. Je suis sûr qu'il existe un moyen simple de le faire avec cette approche mais je n'ai pas touché au code android depuis le premier trimestre 2014. Peut-être que vous souhaitez utiliser une deuxième catégorie pour ce cas? Ou un drapeau? Mais je suppose que son ment fonctionne comme ça. Que diriez-vous de démarrer l'activité principale et d'ajouter une sorte de méta-info pour ouvrir l'activité correcte alors?
A. Binzxxxxxx
2

J'ai créé une classe de base pour toutes mes activités, étendant l' AppCompatActivity , et qui a un compteur statique:

public abstract class BasicActivity extends AppCompatActivity {
    private static int activityCounter = 0;

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        --activityCounter;
        if(activityCounter==0) {
            // Last instance code...
        }
    }

    public boolean isLastInstance() { return (activityCounter==1); }
}

Cela a assez bien fonctionné jusqu'à présent; et quelle que soit la version de l'API. Il faut bien sûr que toutes les activités étendent cette classe de base - ce qu'elles font, dans mon cas.

Edit: J'ai remarqué une instance lorsque le compteur descend à zéro avant la fermeture complète de l'application, c'est-à-dire lorsque l'orientation est modifiée et qu'une seule activité est ouverte. Lorsque l'orientation change, l'activité est fermée et une autre est créée, ainsi onDestroyedest appelée pour la dernière activité, puis onCreateest appelée lorsque la même activité est créée avec l'orientation modifiée. Ce comportement doit être pris en compte; OrientationEventListener pourrait éventuellement être utilisé.

Per Löwgren
la source
0

Android implémente une pile d'activité, je vous suggère de lire ici . On dirait que tout ce que vous voulez faire bien est - extraient l'activité d'appel: getCallingActivity(). Si l'activité en cours est la première activité de votre application et que l'application a été lancée depuis l'écran d'accueil, elle devrait (je suppose) revenir null.

Gyan alias Gary Buyn
la source
9
Cela ne fonctionnera pas car getCallingActivity () retournera null si l'activité n'a pas été démarrée via startActivityForResult ().
H9kDroid
0

La seule chose qui a manqué ici, c'est le clic "Touche Accueil", une fois activé, vous ne pouvez pas le détecter à partir de votre activité, il serait donc préférable de contrôler la pile d'activités par programme en gérant la "touche Retour", appuyez et passez à l'activité requise ou juste faire les étapes nécessaires.

En outre, vous ne pouvez pas être sûr que le démarrage de votre activité à partir de la liste "Activité récente" peut être détecté en prédéfinissant des données supplémentaires dans l'intention d'ouverture de l'activité, car elles sont réutilisées dans ce cas.

ACM64
la source