¿Cómo puedo saber si la aplicación de Android se está ejecutando en primer plano?

Estoy haciendo una notificación de barra de estado en mi aplicación de Android que se desencadena por c2dm. No quiero mostrar la notificación si la aplicación se está ejecutando. ¿Cómo se determina si la aplicación se está ejecutando y está en primer plano?

Cree una variable global como private boolean mIsInForegroundMode; y asigne un valor false en onPause() y un valor true en onResume() .

Código de muestra:

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

Alternativamente, puede consultar con el ActivityManager qué tareas están ejecutando el método getRunningTasks . Luego verifique con la primera tarea (tarea en primer plano) en la Lista de tareas devuelta, si es su tarea.
Aquí está el ejemplo del código:

 public Notification buildNotification(String 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().toString() .equalsIgnoreCase(appContext.getPackageName().toString())) { isActivityFound = true; } if (isActivityFound) { return null; } else { // write your code to build a notification. // return the notification you built here } } 

Y no olvide agregar el permiso GET_TASKS en el archivo manifest.xml para poder ejecutar el método getRunningTasks() en el código anterior:

  

p / s: si está de acuerdo de esta manera, tenga en cuenta que este permiso ahora está en desuso.

Esta es una publicación bastante antigua, pero aún bastante relevante. La solución aceptada anteriormente puede funcionar, pero es incorrecta. Como Dianne Hackborn escribió:

Estas API no están ahí para que las aplicaciones basen su flujo de IU, sino para hacer cosas como mostrarle al usuario las aplicaciones en ejecución, o un administrador de tareas, etc.

Sí, hay una lista guardada en la memoria para estas cosas. Sin embargo, está desactivado en otro proceso, administrado por hilos que se ejecutan por separado del suyo, y no es algo con lo que puede contar (a) ver a tiempo para tomar la decisión correcta o (b) tener una imagen consistente para el momento en que regrese. Además, la decisión sobre a qué se dirige la “próxima” actividad siempre se lleva a cabo en el punto en el que va a suceder el cambio, y no es hasta ese punto exacto (donde el estado de la actividad se bloquea brevemente para hacer el cambio) que En realidad, sé por lo que será lo siguiente.

Y la implementación y el comportamiento global aquí no se garantiza que permanezcan iguales en el futuro.

La solución correcta es implementar: ActivityLifeCycleCallbacks .

Esto básicamente necesita una clase de aplicación y el controlador se puede configurar allí para identificar el estado de sus actividades en la aplicación.

Como dice Vinay, probablemente la mejor solución (para admitir nuevas versiones de Android, 14+) es usar ActivityLifecycleCallbacks en la implementación de la clase de aplicación.

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

Y en el onCreate() Application onCreate() :

 registerActivityLifecycleCallbacks(new ApplicationLifecycleManager()); 

Luego, ApplicationLifecycleManager.isAppVisible() o ApplicationLifecycleManager.isAppInForeground() se usarían para conocer el estado deseado.

FYI, si usas la solución de Gadenkan (¡lo cual es genial!) No olvides agregar

  

al manifiesto

Desde la API 16 puedes hacerlo así:

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

Versión ligeramente limpiada de la solución de Gadenkan . Ponga cualquier actividad, o tal vez una clase base para todas sus actividades.

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

Para poder llamar a getRunningTasks() , debe agregar esto en su AndroidManifest.xml :

  

Sin embargo, tenga en cuenta lo que ActivityManager.getRunningTasks() dice Javadoc:

Nota: este método solo está destinado a depurar y presentar interfaces de usuario de administración de tareas. Esto nunca debe usarse para la lógica central en una aplicación, como decidir entre diferentes comportamientos según la información que se encuentra aquí. Tales usos no son compatibles, y es probable que se rompan en el futuro.

Actualización (febrero de 2015)

Tenga en cuenta que getRunningTasks() se desaprobó en API nivel 21 .

A partir de LOLLIPOP , este método ya no está disponible para aplicaciones de terceros: la introducción de elementos centrados en el documento significa que puede filtrar información de la persona a la persona que llama. Para compatibilidad con versiones anteriores, aún devolverá un pequeño subconjunto de sus datos: al menos las tareas propias de la persona que llama, y ​​posiblemente algunas otras tareas como el hogar que se sabe que no son sensibles.

Entonces, lo que escribí antes es aún más relevante:

En muchos casos, probablemente puedas encontrar una mejor solución. Por ejemplo, hacer algo en onPause() y onResume() , quizás en una BaseActivity para todas sus actividades.

(En nuestro caso, no deseamos que se inicie una actividad de alerta fuera de línea si no estamos en primer plano, por lo que en BaseActivity onPause() simplemente nos damos de baja de la Subscription RxJava para escuchar la señal de “se desconectó”).

Siguiendo la respuesta de Gadenkan, necesitaba algo como esto para poder decir si mi aplicación no se estaba ejecutando en primer plano, pero necesitaba algo que fuera extenso a la aplicación y no me exigía configurar / desactivar indicadores en toda mi aplicación.

El código de Gadenkan casi golpeó el clavo en la cabeza, pero no fue en mi propio estilo y sentí que podría estar más ordenado, por lo que en mi aplicación se condensa hasta esto.

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

(Nota al margen: simplemente puede eliminar el! Si desea que el cheque funcione al revés)

Aunque con este enfoque, necesita el permiso GET_TASKS .

Me gustaría agregar que una forma más segura de hacerlo, que verificar si su aplicación está en segundo plano antes de crear una notificación, es simplemente deshabilitar y habilitar el Receptor de difusión en Pausa () y en Repetición (), respectivamente.

Este método le da más control en la lógica de la aplicación real y no es probable que cambie en el futuro.

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

Encontré una manera más simple y precisa de verificar si la aplicación está en primer plano o en segundo plano asignando las actividades a boolean.

Compruebe la esencia completa aquí

Esto es útil solo cuando desea realizar alguna acción justo cuando comienza su actividad y es cuando desea verificar si la aplicación está en primer plano o en segundo plano.

En lugar de usar el administrador de actividades, hay un truco simple que puedes hacer a través del código. Si observa el ciclo de actividad de cerca, el flujo entre dos actividades y el primer plano al fondo es el siguiente. Supongamos que A y B son dos actividades.

Cuando se pasa de A a B: 1. onPause () de A se llama 2. onResume () de B se llama 3. onStop () de A se llama cuando B se reanuda por completo

Cuando la aplicación entra en segundo plano: 1. se llama onPause () de A 2. se llama 2. onStop () de A

Puedes detectar tu evento de fondo simplemente poniendo una bandera en actividad.

Realice una actividad abstracta y extiéndala de sus otras actividades, de modo que no tenga que copiar y pegue el código para todas las demás actividades donde sea que necesite el evento de fondo.

En actividad abstracta, cree el indicador isAppInBackground.

En el método onCreate (): isAppInBackground = false;

En el método onPause (): isAppInBackground = false;

En el método onStop (): isAppInBackground = true;

Solo necesita comprobar su onResume () si isAppInBackground es verdadero. n después de que verifique su bandera, vuelva a configurar isAppInBackground = false

Para la transición entre dos actividades desde onSTop () de primero siempre se llamará después de que se reanude la segunda actividad, la bandera nunca será verdadera y cuando la aplicación esté en segundo plano, se llamará a onStop () de actividad inmediatamente después de onPause y por lo tanto la bandera será verdadera cuando abre la aplicación más tarde.

Sin embargo, hay un escenario más en este enfoque. Si alguna de las pantallas de su aplicación ya está abierta y coloca el móvil inactivo, después de un tiempo, el móvil pasará al modo de suspensión y, cuando desbloquee el dispositivo móvil, se tratará en un evento de segundo plano.

Este es un método que uso (y el método de apoyo):

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

En función de las diversas respuestas y comentarios, aquí hay una versión más en línea que puede agregar a una clase de ayuda:

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

Como se menciona en otras respuestas, debe agregar el siguiente permiso a su AndroidManifest.xml .

  

Aquí está el código de la solución simple y agradable descrita anteriormente por @ user2690455. Aunque parece un poco detallado, verás que en general es bastante liviano

En mi caso también usamos AppCompatActivity, así que tuve que tener 2 clases 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; } } 

No hay callback global para esto, pero para cada actividad es onStop (). No es necesario que te metas con una int atómica. Solo tiene un int global con la cantidad de actividades iniciadas, en cada actividad incremente en onStart () y disminuya en onStop ().

Sigue esto

  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().toString().equalsIgnoreCase(context.getPackageName().toString())) { return true; } return false; } 

Los enfoques anteriores mencionados aquí no son óptimos. El enfoque basado en tareas requiere un permiso que podría no ser deseado y el enfoque “booleano” es propenso a errores de modificación concurrentes.

El enfoque que uso y que (creo) funciona bastante bien en la mayoría de los casos:

Tener una clase “MainApplication” para rastrear el recuento de actividades en 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(); } } } 

Y crea una clase de actividad base que otras actividades extenderían:

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