Comment puis-je savoir si l’application Android est en cours d’exécution au premier plan?

Je fais une notification de barre d’état dans mon application Android qui est déclenchée par c2dm. Je ne veux pas afficher la notification si l’application est en cours d’exécution. Comment déterminez-vous si l’application est en cours d’exécution et est au premier plan?

Créez une variable globale comme private boolean mIsInForegroundMode; et atsortingbuez une valeur false dans onPause() et une valeur true dans onResume() .

Exemple de code:

 private boolean mIsInForegroundMode; @Override protected void onPause() { super.onPause(); mIsInForegroundMode = false; } @Override protected void onResume() { super.onResume(); mIsInForegroundMode = true; } // Some function. public boolean isInForeground() { return mIsInForegroundMode; } 

Vous pouvez également vérifier avec ActivityManager quelles tâches sont exécutées par la méthode getRunningTasks . Ensuite, vérifiez avec la première tâche (tâche au premier plan) dans la liste des tâches renvoyée, si c’est votre tâche.
Voici l’exemple de code:

 public Notification buildNotification(Ssortingng arg0, Map arg1) { ActivityManager activityManager = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE); List services = activityManager .getRunningTasks(Integer.MAX_VALUE); boolean isActivityFound = false; if (services.get(0).topActivity.getPackageName().toSsortingng() .equalsIgnoreCase(appContext.getPackageName().toSsortingng())) { isActivityFound = true; } if (isActivityFound) { return null; } else { // write your code to build a notification. // return the notification you built here } } 

Et n’oubliez pas d’append l’autorisation GET_TASKS dans le fichier manifest.xml pour pouvoir exécuter la méthode getRunningTasks() dans le code ci-dessus:

  

p / s: Si vous êtes d’accord, notez que cette permission est maintenant obsolète.

Ceci est un très vieux post mais toujours très pertinent. La solution acceptée ci-dessus peut fonctionner mais est incorrecte. Comme Dianne Hackborn a écrit:

Ces API ne sont pas là pour que les applications basent leur stream d’interface utilisateur, mais pour faire des choses comme montrer à l’utilisateur les applications en cours d’exécution, un gestionnaire de tâches, etc.

Oui, il y a une liste gardée en mémoire pour ces choses. Cependant, il est désactivé dans un autre processus, géré par des threads s’exécutant séparément des vôtres, et pas quelque chose sur lequel vous pouvez (a) voir à temps pour prendre la bonne décision ou (b) avoir une image cohérente au moment de votre retour. De plus, la décision concernant la prochaine activité à effectuer se fait toujours au point où le changement doit avoir lieu, et ce n’est qu’à ce moment précis (où l’état de l’activité est brièvement verrouillé pour effectuer le changement) savoir réellement pour ce que la prochaine chose sera.

Et la mise en œuvre et le comportement global ici ne sont pas garantis pour restr les mêmes à l’avenir.

La solution correcte consiste à implémenter: ActivityLifeCycleCallbacks .

Cela nécessite essentiellement une classe d’application et le gestionnaire peut être configuré pour identifier l’état de vos activités dans l’application.

Comme le dit Vinay, la meilleure solution (pour prendre en charge les nouvelles versions Android, 14+) est probablement d’utiliser ActivityLifecycleCallbacks dans l’implémentation de la classe Application .

 package com.telcel.contenedor.appdelegate; import android.app.Activity; import android.app.Application.ActivityLifecycleCallbacks; import android.os.Bundle; /** Determines global app lifecycle states. * * The following is the reference of activities states: * * The visible lifetime of an activity happens between a call to onStart() * until a corresponding call to onStop(). During this time the user can see the * activity on-screen, though it may not be in the foreground and interacting with * the user. The onStart() and onStop() methods can be called multiple times, as * the activity becomes visible and hidden to the user. * * The foreground lifetime of an activity happens between a call to onResume() * until a corresponding call to onPause(). During this time the activity is in front * of all other activities and interacting with the user. An activity can frequently * go between the resumed and paused states -- for example when the device goes to * sleep, when an activity result is delivered, when a new intent is delivered -- * so the code in these methods should be fairly lightweight. * * */ public class ApplicationLifecycleManager implements ActivityLifecycleCallbacks { /** Manages the state of opened vs closed activities, should be 0 or 1. * It will be 2 if this value is checked between activity B onStart() and * activity A onStop(). * It could be greater if the top activities are not fullscreen or have * transparent backgrounds. */ private static int visibleActivityCount = 0; /** Manages the state of opened vs closed activities, should be 0 or 1 * because only one can be in foreground at a time. It will be 2 if this * value is checked between activity B onResume() and activity A onPause(). */ private static int foregroundActivityCount = 0; /** Returns true if app has foreground */ public static boolean isAppInForeground(){ return foregroundActivityCount > 0; } /** Returns true if any activity of app is visible (or device is sleep when * an activity was visible) */ public static boolean isAppVisible(){ return visibleActivityCount > 0; } public void onActivityCreated(Activity activity, Bundle bundle) { } public void onActivityDestroyed(Activity activity) { } public void onActivityResumed(Activity activity) { foregroundActivityCount ++; } public void onActivityPaused(Activity activity) { foregroundActivityCount --; } public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } public void onActivityStarted(Activity activity) { visibleActivityCount ++; } public void onActivityStopped(Activity activity) { visibleActivityCount --; } } 

Et dans la onCreate() Application onCreate() :

 registerActivityLifecycleCallbacks(new ApplicationLifecycleManager()); 

ApplicationLifecycleManager.isAppVisible() ou ApplicationLifecycleManager.isAppInForeground() seront ensuite utilisés pour connaître l’état souhaité.

FYI, si vous utilisez la solution Gadenkan (ce qui est génial !!), n’oubliez pas d’append

  

au manifeste.

Depuis l’API 16, vous pouvez le faire comme ceci:

 static boolean shouldShowNotification(Context context) { RunningAppProcessInfo myProcess = new RunningAppProcessInfo(); ActivityManager.getMyMemoryState(myProcess); if (myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND) return true; KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); // app is in foreground, but if screen is locked show notification anyway return km.inKeyguardRessortingctedInputMode(); } 

Version légèrement nettoyée de la solution de Gadenkan . Mettez une activité ou une classe de base pour toutes vos activités.

 protected boolean isRunningInForeground() { ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List tasks = manager.getRunningTasks(1); if (tasks.isEmpty()) { return false; } Ssortingng topActivityName = tasks.get(0).topActivity.getPackageName(); return topActivityName.equalsIgnoreCase(getPackageName()); } 

Pour pouvoir appeler getRunningTasks() , vous devez append ceci dans votre AndroidManifest.xml :

  

Notez ce que ActivityManager.getRunningTasks() Javadoc dit cependant:

Remarque: cette méthode est uniquement destinée au débogage et à la présentation des interfaces utilisateur de gestion des tâches. Cela ne devrait jamais être utilisé pour une logique de base dans une application, par exemple pour choisir entre différents comportements en fonction des informations trouvées ici. Ces utilisations ne sont pas sockets en charge et risquent de se briser à l’avenir.

Mise à jour (février 2015)

Notez que getRunningTasks() est getRunningTasks() obsolète au niveau 21 de l’API !

Comme pour LOLLIPOP , cette méthode n’est plus disponible pour les applications tierces: l’introduction de recents centrés sur les documents signifie qu’ils peuvent transmettre des informations sur les personnes à l’appelant. Pour assurer la rétrocompatibilité, il renverra toujours un petit sous-ensemble de ses données: au moins les propres tâches de l’appelant, et éventuellement d’autres tâches telles que celles qui ne sont pas sensibles.

Donc, ce que j’ai écrit plus tôt est encore plus pertinent:

Dans de nombreux cas, vous pouvez probablement trouver une meilleure solution. Par exemple, faire quelque chose dans onPause() et onResume() , peut-être dans une BaseActivity pour toutes vos activités.

(Dans notre cas, nous ne voulions pas qu’une activité d’alerte hors ligne soit lancée si nous ne sums pas au premier plan, alors dans BaseActivity onPause() nous nous désabonnons simplement de l’ Subscription RxJava en écoutant le signal “déconnecté”.)

Suite à la réponse de Gadenkan, j’avais besoin de quelque chose comme ça pour que je puisse savoir si mon application ne fonctionnait pas au premier plan, mais j’avais besoin de quelque chose qui ne nécessitait pas que je mette en place des indicateurs.

Le code de Gadenkan a vraiment frappé le clou mais ce n’était pas dans mon propre style et il a senti que ça pouvait être plus net, donc dans mon application, ça se résume à ceci.

 if (!context.getPackageName().equalsIgnoreCase(((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(1).get(0).topActivity.getPackageName())) { // App is not in the foreground } 

(Note latérale: vous pouvez simplement supprimer le! Si vous voulez que le chèque fonctionne dans l’autre sens)

Bien qu’avec cette approche, vous avez besoin de l’autorisation GET_TASKS .

J’aimerais append qu’un moyen plus sûr de le faire – que de vérifier si votre application est en arrière-plan avant de créer une notification – consiste à désactiver et à activer respectivement le récepteur de diffusion onPause () et onResume ().

Cette méthode vous donne plus de contrôle sur la logique applicative réelle et ne risque pas de changer dans le futur.

 @Override protected void onPause() { unregisterReceiver(mHandleMessageReceiver); super.onPause(); } @Override protected void onResume() { super.onResume(); registerReceiver(mHandleMessageReceiver, new IntentFilter(DISPLAY_MESSAGE_ACTION)); } 

J’ai trouvé un moyen plus simple et plus précis de vérifier si l’application est en avant-plan ou en arrière-plan en mappant les activités sur booléen.

Vérifiez l’intégralité de la liste ici

Ceci n’est utile que lorsque vous souhaitez effectuer une action juste au début de votre activité et à quel endroit vous souhaitez vérifier si l’application est au premier plan ou en arrière-plan.

Au lieu d’utiliser le gestionnaire d’activité, il existe un truc simple que vous pouvez faire grâce au code. Si vous observez le cycle d’activité de près, le stream entre deux activités et l’avant-plan à l’arrière-plan est le suivant. Supposons que A et B sont deux activités.

Lors de la transition de A à B: 1. onPause () de A s’appelle 2. onResume () de B s’appelle 3. onStop () de A est appelée quand B reprend entièrement

Lorsque l’application entre en arrière-plan: 1. onPause () de A s’appelle 2. onStop () de A s’appelle

Vous pouvez détecter votre événement en arrière-plan en mettant simplement un drapeau en activité.

Créez une activité abstraite et étendez-la à partir de vos autres activités afin de ne pas avoir à copier coller le code pour toutes les autres activités, quel que soit l’endroit où vous avez besoin d’événement d’arrière-plan.

Dans l’activité abstraite, créer un indicateur isAppInBackground.

Dans la méthode onCreate (): isAppInBackground = false;

Dans la méthode onPause (): isAppInBackground = false;

Dans la méthode onStop (): isAppInBackground = true;

Vous devez simplement vérifier votre onResume () si isAppInBackground est vrai. n après avoir vérifié votre drapeau puis à nouveau défini isAppInBackground = false

Pour la transition entre deux activités puisque onSTop () du premier sera toujours appelé après la reprise de la seconde activité, le drapeau ne sera jamais vrai et lorsque l’application est en arrière-plan, onStop () sera appelé immédiatement après onPause et le drapeau sera donc vrai lorsque vous ouvrez l’application plus tard.

Il y a un autre scénario dans cette approche. Si l’un des écrans de votre application est déjà ouvert et que vous mettez le téléphone en veille, le téléphone passera ensuite en mode veille et, lorsque vous déverrouillerez le téléphone portable, il sera traité lors d’un événement en arrière-plan.

Voici une méthode que j’utilise (et méthode à suivre):

 private boolean checkIfAppIsRunningInForeground() { ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); for(ActivityManager.RunningAppProcessInfo appProcessInfo : activityManager.getRunningAppProcesses()) { if(appProcessInfo.processName.contains(this.getPackageName())) { return checkIfAppIsRunningInForegroundByAppImportance(appProcessInfo.importance); } } return false; } private boolean checkIfAppIsRunningInForegroundByAppImportance(int appImportance) { switch (appImportance) { //user is aware of app case ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND: case ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE: return true; //user is not aware of app case ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND: case ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY: case ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE: case ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE: default: return false; } } 

Sur la base des différentes réponses et commentaires, voici une version plus détaillée que vous pouvez append à une classe d’assistance:

 public static boolean isAppInForeground(Context context) { List task = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)) .getRunningTasks(1); if (task.isEmpty()) { return false; } return task .get(0) .topActivity .getPackageName() .equalsIgnoreCase(context.getPackageName()); } 

Comme mentionné dans d’autres réponses, vous devez append la permission suivante à votre AndroidManifest.xml .

  

Voici le code de la solution simple décrite ci-dessus par @ user2690455. Bien que cela semble un peu verbeux, vous verrez que c’est en fait assez léger

Dans mon cas, nous utilisons également AppCompatActivity, donc je devais avoir 2 classes de base.

 public class BaseActivity extends Activity { /** * Let field be set only in base class * All callers must use accessors, * and then it's not up to them to manage state. * * Making it static since .. * 1. It needs to be used across two base classes * 2. It's a singleton state in the app */ private static boolean IS_APP_IN_BACKGROUND = false; @Override protected void onResume() { super.onResume(); BaseActivity.onResumeAppTracking(this); BaseActivity.setAppInBackgroundFalse(); } @Override protected void onStop() { super.onStop(); BaseActivity.setAppInBackgroundTrue(); } @Override protected void onPause() { super.onPause(); BaseActivity.setAppInBackgroundFalse(); } protected static void onResumeAppTracking(Activity activity) { if (BaseActivity.isAppInBackground()) { // do requirements for returning app to foreground } } protected static void setAppInBackgroundFalse() { IS_APP_IN_BACKGROUND = false; } protected static void setAppInBackgroundTrue() { IS_APP_IN_BACKGROUND = true; } protected static boolean isAppInBackground() { return IS_APP_IN_BACKGROUND; } } 

Il n’y a pas de rappel global pour cela, mais pour chaque activité, il s’agit de onStop (). Vous n’avez pas besoin de jouer avec un int atomique. Il suffit d’avoir un int global avec le nombre d’activités démarrées, dans chaque activité, incrémentez-le dans onStart () et décrémentez-le dans onStop ().

Suivez ceci

  public static boolean isAppRunning(Context context) { // check with the first task(task in the foreground) // in the returned list of tasks ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List services = activityManager.getRunningTasks(Integer.MAX_VALUE); if (services.get(0).topActivity.getPackageName().toSsortingng().equalsIgnoreCase(context.getPackageName().toSsortingng())) { return true; } return false; } 

Les approches précédentes mentionnées ici ne sont pas optimales. L’approche basée sur les tâches nécessite une autorisation qui pourrait ne pas être souhaitée et l’approche “booléenne” est sujette à des modifications simultanées.

L’approche que j’utilise et qui (je crois) fonctionne assez bien dans la plupart des cas:

Avoir une classe “MainApplication” pour suivre le nombre d’activités dans AtomicInteger :

 import android.app.Application; import java.util.concurrent.atomic.AtomicInteger; public class MainApplication extends Application { static class ActivityCounter { private static AtomicInteger ACTIVITY_COUNT = new AtomicInteger(0); public static boolean isAppActive() { return ACTIVITY_COUNT.get() > 0; } public static void activityStarted() { ACTIVITY_COUNT.incrementAndGet(); } public static void activityStopped() { ACTIVITY_COUNT.decrementAndGet(); } } } 

Et créez une classe d’activité de base que d’autres activités pourraient étendre:

 import android.app.Activity; import android.support.annotation.CallSuper; public class TestActivity extends Activity { @Override @CallSuper protected void onStart() { MainApplication.ActivityCounter.activityStarted(); super.onStart(); } @Override @CallSuper protected void onStop() { MainApplication.ActivityCounter.activityStopped(); super.onStop(); } }