Verifica si una aplicación de Android se ejecuta en segundo plano

Por antecedentes, me refiero a que ninguna de las actividades de la aplicación está actualmente visible para el usuario.

Hay pocas maneras de detectar si su aplicación se ejecuta en segundo plano, pero solo una de ellas es completamente confiable:

  1. La solución correcta (los créditos van a Dan , CommonsWare y NeTeInStEiN )
    Haga un seguimiento de la visibilidad de su aplicación usando los métodos Activity.onPause , Activity.onResume . Almacenar el estado de “visibilidad” en alguna otra clase. Las buenas elecciones son su propia implementación de la Application o un Service (también hay algunas variaciones de esta solución si desea verificar la visibilidad de la actividad desde el servicio).

    Ejemplo
    Implementar clase de Application personalizada (tenga en cuenta el isActivityVisible() static):

     public class MyApplication extends Application { public static boolean isActivityVisible() { return activityVisible; } public static void activityResumed() { activityVisible = true; } public static void activityPaused() { activityVisible = false; } private static boolean activityVisible; } 

    Registre su clase de aplicación en AndroidManifest.xml :

      

    Agregue onPause y onResume a cada Activity en el proyecto (puede crear un ancestro común para sus actividades si lo desea, pero si su actividad ya está extendida desde MapActivity / ListActivity , debe escribir lo siguiente a mano) :

     @Override protected void onResume() { super.onResume(); MyApplication.activityResumed(); } @Override protected void onPause() { super.onPause(); MyApplication.activityPaused(); } 

    Actualizar
    Se agregaron ActivityLifecycleCallbacks en API nivel 14 (Android 4.0). Puede usarlos para rastrear si una actividad de su aplicación está actualmente visible para el usuario. Verifique la respuesta de Cornstalks a continuación para los detalles.

  2. El equivocado
    Yo solía sugerir la siguiente solución:

    Puede detectar la aplicación actualmente en primer plano / fondo con ActivityManager.getRunningAppProcesses() que devuelve una lista de registros RunningAppProcessInfo . Para determinar si su aplicación está en primer plano, compruebe el campo RunningAppProcessInfo.importance para la igualdad con RunningAppProcessInfo.IMPORTANCE_FOREGROUND mientras RunningAppProcessInfo.processName es igual al nombre del paquete de la aplicación.

    Además, si llama a ActivityManager.getRunningAppProcesses() desde el subproceso UI de su aplicación, devolverá importancia IMPORTANCE_FOREGROUND para su tarea, sin importar si está realmente en primer plano o no. Llámalo en el hilo de fondo (por ejemplo, a través de AsyncTask ) y devolverá los resultados correctos.

    Si bien esta solución puede funcionar (y de hecho funciona la mayor parte del tiempo), recomiendo abstenerse de usarla. Y aquí está el por qué. 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é con certeza cuál será la próxima cosa.

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

    Desearía haber leído esto antes de publicar una respuesta en el SO, pero espero que no sea demasiado tarde para admitir mi error.

  3. Otra solución incorrecta
    La biblioteca Droid-Fu mencionada en una de las respuestas usa ActivityManager.getRunningTasks para su método isApplicationBroughtToBackground . Vea el comentario anterior de Dianne y tampoco use ese método.

La clave es usar ActivityLifecycleCallbacks (tenga en cuenta que esto requiere Android API nivel 14 (Android 4.0)). Simplemente verifica si el número de actividades detenidas es igual al número de actividades iniciadas. Si son iguales, tu aplicación estará en segundo plano. Si hay más actividades iniciadas, su aplicación aún es visible. Si hay más actividades reanudadas que pausadas, su aplicación no solo es visible, sino que también está en primer plano. Hay 3 estados principales en los que su actividad puede estar, luego: visible y en primer plano, visible pero no en primer plano, y no visible y no en primer plano (es decir, en el fondo).

Lo realmente bueno de este método es que no tiene los problemas asincrónicos getRunningTasks() , pero tampoco tiene que modificar cada Activity en su aplicación para establecer / onResumed() algo en onResumed() / onPaused() . Son solo unas pocas líneas de código que son independientes y funcionan a lo largo de toda su aplicación. Además, no hay permisos funky requeridos tampoco.

MyLifecycleHandler.java:

 public class MyLifecycleHandler implements ActivityLifecycleCallbacks { // I use four separate variables here. You can, of course, just use two and // increment/decrement them instead of using four and incrementing them all. private int resumed; private int paused; private int started; private int stopped; @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { } @Override public void onActivityDestroyed(Activity activity) { } @Override public void onActivityResumed(Activity activity) { ++resumed; } @Override public void onActivityPaused(Activity activity) { ++paused; android.util.Log.w("test", "application is in foreground: " + (resumed > paused)); } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityStarted(Activity activity) { ++started; } @Override public void onActivityStopped(Activity activity) { ++stopped; android.util.Log.w("test", "application is visible: " + (started > stopped)); } // If you want a static function you can use to check if your application is // foreground/background, you can use the following: /* // Replace the four variables above with these four private static int resumed; private static int paused; private static int started; private static int stopped; // And these two public static functions public static boolean isApplicationVisible() { return started > stopped; } public static boolean isApplicationInForeground() { return resumed > paused; } */ } 

MyApplication.java:

 // Don't forget to add it to your manifest by doing //  

@Mewzer me ha hecho algunas buenas preguntas sobre este método a las que me gustaría responder en esta respuesta para todos:

onStop() no se llama en situaciones de poca memoria; ¿Es ese un problema aquí?

No. Los documentos para onStop() dicen:

Tenga en cuenta que nunca se puede llamar a este método, en situaciones de memoria baja donde el sistema no tiene memoria suficiente para mantener el proceso de su actividad ejecutándose después de que se llame al método onPause ().

La clave aquí es "mantener en funcionamiento el proceso de su actividad ..." Si se llega a esta situación de poca memoria, su proceso se cancela (no solo su actividad). Esto significa que este método de verificación de fondo aún es válido porque a) no se puede verificar el fondo de todos modos si se mata su proceso, yb) si el proceso comienza de nuevo (porque se crea una nueva actividad), el miembro las variables (ya sean estáticas o no) para MyLifecycleHandler se restablecerán a 0 .

¿Funciona esto para los cambios de configuración?

Por defecto, no. Tiene que establecer explícitamente configChanges=orientation|screensize ( | con cualquier otra cosa que desee) en su archivo de manifiesto y manejar los cambios de configuración, de lo contrario su actividad será destruida y recreada. Si no configura esto, se onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume los métodos de su actividad en este orden: onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume . Como puede ver, no hay superposición (normalmente, dos actividades se superponen muy brevemente al cambiar entre las dos, que es así como funciona este método de detección de fondo). Para evitar esto, debe establecer configChanges para que su actividad no se destruya. Afortunadamente, he tenido que configurar configChanges en todos mis proyectos porque no era deseable que toda mi actividad se destruyera en la pantalla rotar / cambiar el tamaño, por lo que nunca he encontrado que esto sea problemático. (¡Gracias a dpimka por refrescar mi memoria y corregirme!)

Una nota:

Cuando mencioné "antecedentes" aquí en esta respuesta, quise decir "su aplicación ya no está visible". Las actividades de Android pueden ser visibles pero no estar en primer plano (por ejemplo, si hay una superposición transparente de notificaciones). Es por eso que he actualizado esta respuesta para reflejar eso.

Es importante saber que Android tiene un momento de limbo raro cuando se cambian las actividades donde nada está en primer plano . Por este motivo, si comprueba si su aplicación está en primer plano al cambiar de actividades (en la misma aplicación), se le informará que no está en primer plano (aunque su aplicación siga siendo activa y esté visible). )

Puede verificar si su aplicación está en primer plano en el método super.onPause() su Activity después de super.onPause() . Solo recuerda el extraño estado del limbo del que acabo de hablar.

Puede verificar si su aplicación es visible (es decir, si no está en segundo plano) en el método super.onStop() su Activity después de super.onStop() .

La respuesta de Idolon es propensa a errores y mucho más complicada aunque cabe preguntarse si la aplicación de Android está en primer plano o no. y aquí Determinar la aplicación de primer plano actual desde una tarea o servicio en segundo plano

Hay un enfoque mucho más simple:

En una actividad base que todas las actividades se extienden:

 protected static boolean isVisible = false; @Override public void onResume() { super.onResume(); setVisible(true); } @Override public void onPause() { super.onPause(); setVisible(false); } 

Siempre que necesite verificar si alguna de sus actividades de aplicación está en primer plano, simplemente marque isVisible() ;

Para comprender este enfoque, verifique esta respuesta del ciclo de vida de la actividad side-by-side : Actividad ciclo de vida lado a lado

SOLUCIÓN DE GOOGLE : no es un truco, como las soluciones anteriores. Use ProcessLifecycleOwner

 class ArchLifecycleApp : Application(), LifecycleObserver { override fun onCreate() { super.onCreate() ProcessLifecycleOwner.get().lifecycle.addObserver(this) } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun onAppBackgrounded() { //App in background } @OnLifecycleEvent(Lifecycle.Event.ON_START) fun onAppForegrounded() { // App in foreground } } 

en app.gradle

 dependencies { ... implementation "android.arch.lifecycle:extensions:1.1.0" } allprojects { repositories { ... google() jcenter() maven { url 'https://maven.google.com' } } } 

Desde Android API 16, hay una manera simple de verificar si la aplicación está en primer plano. Puede que no sea infalible, pero ningún método en Android es infalible. Este método es lo suficientemente bueno para usar cuando su servicio recibe la actualización del servidor y tiene que decidir si mostrar o no la notificación (porque si la IU está en primer plano, el usuario notará la actualización sin notificación).

 RunningAppProcessInfo myProcess = new RunningAppProcessInfo(); ActivityManager.getMyMemoryState(myProcess); isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND; 

Probé la solución recomendada que usa Application.ActivityLifecycleCallbacks y muchos otros, pero no funcionaron como se esperaba. Gracias a Sarge , se me ocurrió una solución bastante sencilla y directa que describo a continuación.

La clave de la solución es el hecho de comprender que si tenemos ActivityA y ActivityB, y llamamos ActivityB desde ActivityA (y no llame ActivityA.finish ), entonces se onStart() ActivityB’s onStart() antes de ActivityA onStop() .

Esa es también la principal diferencia entre onStop() y onPause() que ninguno mencionó en los artículos que leí.

Por lo tanto, basándonos en el comportamiento del ciclo de vida de esta actividad, simplemente puede contar cuántas veces se onStart() y onPause() en su progtwig. Tenga en cuenta que para cada Activity de su progtwig, debe anular onStart() y onStop() , para incrementar / disminuir la variable estática utilizada para el conteo. A continuación se muestra el código que implementa esta lógica. Tenga en cuenta que estoy usando una clase que amplía la Application , así que no olvide declarar en Manifest.xml dentro de la etiqueta de la aplicación: android:name=".Utilities" , aunque también se puede implementar usando una clase personalizada simple.

 public class Utilities extends Application { private static int stateCounter; public void onCreate() { super.onCreate(); stateCounter = 0; } /** * @return true if application is on background * */ public static boolean isApplicationOnBackground() { return stateCounter == 0; } //to be called on each Activity onStart() public static void activityStarted() { stateCounter++; } //to be called on each Activity onStop() public static void activityStopped() { stateCounter--; } } 

Ahora en cada actividad de nuestro progtwig, debemos anular onStart() y onStop() e incrementar / disminuir como se muestra a continuación:

 @Override public void onStart() { super.onStart(); Utilities.activityStarted(); } @Override public void onStop() { Utilities.activityStopped(); if(Utilities.isApplicationOnBackground()) { //you should want to check here if your application is on background } super.onStop(); } 

Con esta lógica, hay 2 posibles casos:

  1. stateCounter = 0 : el número de paradas es igual al número de Actividades iniciadas, lo que significa que la aplicación se ejecuta en segundo plano.
  2. stateCounter > 0 : el número de iniciados es mayor que el número de detenidos, lo que significa que la aplicación se ejecuta en primer plano.

Aviso: stateCounter < 0 significaría que hay más actividades detenidas en lugar de iniciadas, lo cual es imposible. Si te encuentras con este caso, significa que no estás aumentando / disminuyendo el contador como deberías.

Estás listo para ir. Debería comprobar si su aplicación está en segundo plano dentro de onStop() .

No es posible, a no ser que lo haga usted mismo, determinar si alguna de sus actividades es visible o no. Tal vez debería considerar hacer una nueva pregunta sobre StackOverflow, explicando qué es lo que está tratando de lograr a partir de la experiencia del usuario, para que tal vez podamos darle ideas alternativas de implementación.

Puede usar ComponentCallbacks2 para detectar si la aplicación está en segundo plano. Por cierto, esta callback solo está disponible en API Nivel 14 (Ice Cream Sandwich) y superior.

Recibirá una llamada al método:

public abstract void onTrimMemory (int level)

si el nivel es ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN , la aplicación está en segundo plano.

Puede implementar esta interfaz para una activity , service , etc.

 public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 { @Override public void onConfigurationChanged(final Configuration newConfig) { } @Override public void onLowMemory() { } @Override public void onTrimMemory(final int level) { if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // app is in background } } } 

Basándose en @Cornstalks responden para incluir un par de características útiles.

Características adicionales:

  • introdujo el patrón singleton para que pueda hacer esto en cualquier lugar de la aplicación: AppLifecycleHandler.isApplicationVisible () y AppLifecycleHandler.isApplicationInForeground ()
  • manejo adicional de eventos duplicados (ver comentarios // tomar algunas medidas sobre el cambio de visibilidad y // tomar algunas medidas sobre el cambio de en primer plano)

App.java

 public class App extends Application { @Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance()); } } 

AppLifecycleHandler.java

 public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks { private int resumed; private int started; private final String DebugName = "AppLifecycleHandler"; private boolean isVisible = false; private boolean isInForeground = false; private static AppLifecycleHandler instance; public static AppLifecycleHandler getInstance() { if (instance == null) { instance = new AppLifecycleHandler(); } return instance; } private AppLifecycleHandler() { } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { } @Override public void onActivityDestroyed(Activity activity) { } @Override public void onActivityResumed(Activity activity) { ++resumed; android.util.Log.w(DebugName, "onActivityResumed -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")"); setForeground((resumed > 0)); } @Override public void onActivityPaused(Activity activity) { --resumed; android.util.Log.w(DebugName, "onActivityPaused -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")"); setForeground((resumed > 0)); } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityStarted(Activity activity) { ++started; android.util.Log.w(DebugName, "onActivityStarted -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")"); setVisible((started > 0)); } @Override public void onActivityStopped(Activity activity) { --started; android.util.Log.w(DebugName, "onActivityStopped -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")"); setVisible((started > 0)); } private void setVisible(boolean visible) { if (isVisible == visible) { // no change return; } // visibility changed isVisible = visible; android.util.Log.w(DebugName, "App Visiblility Changed -> application is visible: " + isVisible); // take some action on change of visibility } private void setForeground(boolean inForeground) { if (isInForeground == inForeground) { // no change return; } // in foreground changed isInForeground = inForeground; android.util.Log.w(DebugName, "App In Foreground Changed -> application is in foreground: " + isInForeground); // take some action on change of in foreground } public static boolean isApplicationVisible() { return AppLifecycleHandler.getInstance().started > 0; } public static boolean isApplicationInForeground() { return AppLifecycleHandler.getInstance().resumed > 0; } } 

Si activa la configuración del desarrollador “No mantener actividades”, compruebe que el recuento de actividades creadas no es suficiente. También debe verificar isSaveInstanceState . Mi método personalizado isApplicationRunning () check es la aplicación de Android se está ejecutando:

Aquí mi código de trabajo:

 public class AppLifecycleService implements Application.ActivityLifecycleCallbacks { private int created; private boolean isSaveInstanceState; private static AppLifecycleService instance; private final static String TAG = AppLifecycleService.class.getName(); public static AppLifecycleService getInstance() { if (instance == null) { instance = new AppLifecycleService(); } return instance; } public static boolean isApplicationRunning() { boolean isApplicationRunning = true; if (getCountCreatedActvities() == 0 && !isSaveInstanceState()) { isApplicationRunning = false; } return isApplicationRunning; } public static boolean isSaveInstanceState() { return AppLifecycleService.getInstance().isSaveInstanceState; } public static int getCountCreatedActvities() { return AppLifecycleService.getInstance().created; } private AppLifecycleService() { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { this.isSaveInstanceState = true; } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { ++created; } @Override public void onActivityDestroyed(Activity activity) { --created; } @Override public void onActivityResumed(Activity activity) { } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } } 

Para aprovechar lo que CommonsWare y Key han dicho, quizás puedas extender la clase Application y hacer que todas tus actividades lo llamen en sus métodos onPause / onResume. Esto le permitiría saber qué Actividad (es) son visibles, pero esto probablemente podría manejarse mejor.

¿Puedes explicar lo que tienes en mente exactamente? Cuando dices correr en segundo plano ¿te refieres simplemente a tener tu aplicación todavía en la memoria a pesar de que no está actualmente en la pantalla? ¿Has considerado el uso de Servicios como una forma más persistente de administrar tu aplicación cuando no está enfocada?

Hice mi propia implementación de ActivityLifecycleCallbacks. Estoy usando SherlockActivity, pero para la clase de actividad normal podría funcionar.

Primero, estoy creando una interfaz que tiene todos los métodos para rastrear el ciclo de vida de las actividades:

 public interface ActivityLifecycleCallbacks{ public void onActivityStopped(Activity activity); public void onActivityStarted(Activity activity); public void onActivitySaveInstanceState(Activity activity, Bundle outState); public void onActivityResumed(Activity activity); public void onActivityPaused(Activity activity); public void onActivityDestroyed(Activity activity); public void onActivityCreated(Activity activity, Bundle savedInstanceState); } 

En segundo lugar, implementé esta interfaz en la clase de mi aplicación:

 public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{ @Override public void onCreate() { super.onCreate(); } @Override public void onActivityStopped(Activity activity) { Log.i("Tracking Activity Stopped", activity.getLocalClassName()); } @Override public void onActivityStarted(Activity activity) { Log.i("Tracking Activity Started", activity.getLocalClassName()); } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName()); } @Override public void onActivityResumed(Activity activity) { Log.i("Tracking Activity Resumed", activity.getLocalClassName()); } @Override public void onActivityPaused(Activity activity) { Log.i("Tracking Activity Paused", activity.getLocalClassName()); } @Override public void onActivityDestroyed(Activity activity) { Log.i("Tracking Activity Destroyed", activity.getLocalClassName()); } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { Log.i("Tracking Activity Created", activity.getLocalClassName()); } } 

Tercero, estoy creando una clase que se extiende desde SherlockActivity:

 public class MySherlockActivity extends SherlockActivity { protected MyApplication nMyApplication; protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); nMyApplication = (MyApplication) getApplication(); nMyApplication.onActivityCreated(this, savedInstanceState); } protected void onResume() { // TODO Auto-generated method stub nMyApplication.onActivityResumed(this); super.onResume(); } @Override protected void onPause() { // TODO Auto-generated method stub nMyApplication.onActivityPaused(this); super.onPause(); } @Override protected void onDestroy() { // TODO Auto-generated method stub nMyApplication.onActivityDestroyed(this); super.onDestroy(); } @Override protected void onStart() { nMyApplication.onActivityStarted(this); super.onStart(); } @Override protected void onStop() { nMyApplication.onActivityStopped(this); super.onStop(); } @Override protected void onSaveInstanceState(Bundle outState) { nMyApplication.onActivitySaveInstanceState(this, outState); super.onSaveInstanceState(outState); } } 

En cuarto lugar, todas las clases que se extienden desde SherlockActivity, las reemplacé por MySherlockActivity:

 public class MainActivity extends MySherlockActivity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } } 

Ahora, en el logcat verá los registros progtwigdos en la implementación de la interfaz realizada en MyApplication.

La mejor solución que he encontrado usa temporizadores.

Ha iniciado un temporizador en onPause () y cancela el mismo temporizador en onResume (), hay 1 instancia del temporizador (generalmente definido en la clase Application). El temporizador en sí está configurado para ejecutar Runnable después de 2 segundos (o el intervalo que creas apropiado), cuando el temporizador se activa estableces un indicador que marca la aplicación como en el fondo.

En el método onResume () antes de cancelar el temporizador, puede consultar el indicador de fondo para realizar cualquier operación de inicio (por ejemplo, iniciar descargas o habilitar servicios de ubicación).

Esta solución le permite tener varias actividades en la stack posterior, y no requiere ningún permiso para implementar.

Esta solución funciona bien si también utiliza un bus de eventos, ya que su temporizador puede simplemente activar un evento y varias partes de su aplicación pueden responder en consecuencia.

La actividad se detiene cuando aparece un cuadro de diálogo, por lo que todas las soluciones recomendadas son soluciones a medias. Necesita crear ganchos para diálogos también.

Dado que aún no se menciona, sugeriré a los lectores que exploren ProcessLifecycleOwner disponible a través de los componentes de la architecture de Android.

Offical docs:

The system distinguishes between foreground and background apps. (The definition of background for purposes of service limitations is distinct from the definition used by memory management; an app might be in the background as pertains to memory management , but in the foreground as pertains to its ability to launch services.) An app is considered to be in the foreground if any of the following is true:

  1. It has a visible activity, whether the activity is started or paused.
  2. It has a foreground service.
  3. Another foreground app is connected to the app, either by binding to one of its services or by making use of one of its content providers. For example, the app is in the foreground if another app binds to its:
    • IME
    • Wallpaper service
    • Notification listener
    • Voice or text service

If none of those conditions is true, the app is considered to be in the background.

In my activities onResume and onPause I write an isVisible boolean to SharedPrefences.

  SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); Editor editor = sharedPrefs.edit(); editor.putBoolean("visible", false); editor.commit(); 

And read it elsewhere when needed via,

  // Show a Toast Notification if App is not visible (ie in background. Not running, etc) SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); if(!sharedPrefs.getBoolean("visible", true)){...} 

Maybe not elegant, but it works for me…

Another solution for this old post (for those that it might help) :


  

 public class BaseApplication extends Application { private class Status { public boolean isVisible = true; public boolean isFocused = true; } private Map activities; @Override public void onCreate() { activities = new HashMap(); super.onCreate(); } private boolean hasVisibleActivity() { for (Status status : activities.values()) if (status.isVisible) return true; return false; } private boolean hasFocusedActivity() { for (Status status : activities.values()) if (status.isFocused) return true; return false; } public void onActivityCreate(Activity activity, boolean isStarting) { if (isStarting && activities.isEmpty()) onApplicationStart(); activities.put(activity, new Status()); } public void onActivityStart(Activity activity) { if (!hasVisibleActivity() && !hasFocusedActivity()) onApplicationForeground(); activities.get(activity).isVisible = true; } public void onActivityWindowFocusChanged(Activity activity, boolean hasFocus) { activities.get(activity).isFocused = hasFocus; } public void onActivityStop(Activity activity, boolean isFinishing) { activities.get(activity).isVisible = false; if (!isFinishing && !hasVisibleActivity() && !hasFocusedActivity()) onApplicationBackground(); } public void onActivityDestroy(Activity activity, boolean isFinishing) { activities.remove(activity); if(isFinishing && activities.isEmpty()) onApplicationStop(); } private void onApplicationStart() {Log.i(null, "Start");} private void onApplicationBackground() {Log.i(null, "Background");} private void onApplicationForeground() {Log.i(null, "Foreground");} private void onApplicationStop() {Log.i(null, "Stop");} } 

 public class MyActivity extends BaseActivity {...} 

 public class BaseActivity extends Activity { private BaseApplication application; @Override protected void onCreate(Bundle state) { application = (BaseApplication) getApplication(); application.onActivityCreate(this, state == null); super.onCreate(state); } @Override protected void onStart() { application.onActivityStart(this); super.onStart(); } @Override public void onWindowFocusChanged(boolean hasFocus) { application.onActivityWindowFocusChanged(this, hasFocus); super.onWindowFocusChanged(hasFocus); } @Override protected void onStop() { application.onActivityStop(this, isFinishing()); super.onStop(); } @Override protected void onDestroy() { application.onActivityDestroy(this, isFinishing()); super.onDestroy(); } } 

See the comment in the onActivityDestroyed function.

Works with SDK target version 14> :

 import android.app.Activity; import android.app.Application; import android.os.Bundle; import android.util.Log; public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks { public static int active = 0; @Override public void onActivityStopped(Activity activity) { Log.i("Tracking Activity Stopped", activity.getLocalClassName()); active--; } @Override public void onActivityStarted(Activity activity) { Log.i("Tracking Activity Started", activity.getLocalClassName()); active++; } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName()); } @Override public void onActivityResumed(Activity activity) { Log.i("Tracking Activity Resumed", activity.getLocalClassName()); active++; } @Override public void onActivityPaused(Activity activity) { Log.i("Tracking Activity Paused", activity.getLocalClassName()); active--; } @Override public void onActivityDestroyed(Activity activity) { Log.i("Tracking Activity Destroyed", activity.getLocalClassName()); active--; // if active var here ever becomes zero, the app is closed or in background if(active == 0){ ... } } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { Log.i("Tracking Activity Created", activity.getLocalClassName()); active++; } } 

You should use a shared preference to store the property and act upon it using service binding from your activities. If you use binding only, (that is never use startService), then your service would run only when you bind to it, (bind onResume and unbind onPause) that would make it run on foreground only, and if you do want to work on background you can use the regular start stop service.

I think this question should be more clear. ¿Cuando? ¿Dónde? What is your specific situation you want to konw if your app is in background?

I just introduce my solution in my way.
I get this done by using the field “importance” of RunningAppProcessInfo class in every activity’s onStop method in my app, which can be simply achieved by providing a BaseActivity for other activities to extend which implements the onStop method to check the value of “importance”. Aquí está el código:

 public static boolean isAppRunning(Context context) { ActivityManager activityManager = (ActivityManager) context .getSystemService(Context.ACTIVITY_SERVICE); List appProcesses = activityManager .getRunningAppProcesses(); for (RunningAppProcessInfo appProcess : appProcesses) { if (appProcess.processName.equals(context.getPackageName())) { if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE) { return true; } } } return false; } 

I recommend reading through this page: http://developer.android.com/reference/android/app/Activity.html

In short, your activity is no longer visible after onStop() has been called.

What about using getApplicationState().isInForeground() ?

In my opinion, many answers introduce a heavy load of code and bring lots of complexity and non-readability.

When people ask on SO how to communicate between a Service and a Activity , I usually advice to use the LocalBroadcastManager .


¿Por qué?

Well, by quoting the docs:

  • You know that the data you are broadcasting won’t leave your app, so don’t need to worry about leaking private data.

  • It is not possible for other applications to send these broadcasts to your app, so you don’t need to worry about having security holes they can exploit.

  • It is more efficient than sending a global broadcast through the system.

Not in the the docs:

  • It does not require external libraries
  • The code is minimal
  • It’s fast to implement and understand
  • No custom self-implemented callbacks / ultra-singleton / intra-process pattern whatsoever…
  • No strong references on Activity , Application , …

Descripción

So, you want to check if any of the Activity is currently in the foreground. You usually do that in a Service , or your Application class.

This means, your Activity objects become the sender of a signal (I’m on / I’m off). Your Service , on the other hand, becomes the Receiver .

There are two moments in which your Activity tells you if it’s going in the foreground or in the background (yes only two… not 6).

When the Activity goes into the foreground, the onResume() method is triggered (also called after onCreate() ).

When the Activity goes in the back, onPause() is called.

These are the moments in which your Activity should send the signal to your Service to describe its state.

In case of multiple Activity ‘s, remember the an Activity goes into the background first, then another one comes into the foreground.

So the situation would be:*

 Activity1 -- send --> Signal:OFF Activity2 -- send --> Signal:ON 

The Service / Application will simply keep listening for those signals and act accordingly.


Code (TLDR)

Your Service must implement a BroadcastReceiver in order to listen for signals.

 this.localBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // received data if Activity is on / off } } public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL") 

Register the Receiver in Service::onCreate()

 @Override protected void onCreate() { LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER); } 

Un-register it in Service::onDestroy()

 @Override protected void onDestroy() { // I'm dead, no need to listen to anything anymore. LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver); } 

Now your Activity ‘s must communicated their state.

In Activity::onResume()

 Intent intent = new Intent(); intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent); 

In Activity::onPause()

 Intent intent = new Intent(); intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent); 

A very, very common situation

Developer: I want to send data from my Service and update the Activity . How do I check if the Activity is in the foreground?

There is usually no need to check if the Activity is in the foreground or not. Just send the data via LocalBroadcastManager from your Service . If the Activity is on, then it will respond and act.

For this very common situation, the Service becomes the sender, and the Activity implements the BroadcastReceiver .

So, create a Receiver in your Activity . Register it in onResume() and un-register it in onPause() . There is no need to use the other life-cycle methods .

Define the Receiver behavior in onReceive() (update ListView, do this, do that, …).

This way the Activity will listen only if it’s in the foreground and nothing will happen if it’s in the back or is destroyed.

In case of multiple Activity ‘s, whichever Activity is on will respond (if they also implement the Receiver ).

If all are in the background, nobody will respond and the signal will simply get lost.

Send the data from the Service via Intent (see code above) by specifying the signal ID.


  • Except for Multi-Window Support . It may be tricky (please test it if needed)…

It might be too late to answer but if somebody comes visiting then here is the solution I suggest, The reason(s) an app wants to know it’s state of being in background or coming to foreground can be many, a few are, 1. To show toasts and notifications when the user is in BG. 2.To perform some tasks for the first time user comes from BG, like a poll, redraw etc.

The solution by Idolon and others takes care of the first part, but does not for the second. If there are multiple activities in your app, and the user is switching between them, then by the time you are in second activity, the visible flag will be false. So it cannot be used deterministically.

I did something what was suggested by CommonsWare, “If the Service determines that there are no activities visible, and it remains that way for some amount of time , stop the data transfer at the next logical stopping point.”

The line in bold is important and this can be used to achieve second item. So what I do is once I get the onActivityPaused() , don not change the visible to false directly, instead have a timer of 3 seconds (that is the max that the next activity should be launched), and if there is not onActivityResumed() call in the next 3 seconds, change visible to false. Similarly in onActivityResumed() if there is a timer then I cancel it. To sum up,the visible becomes isAppInBackground.

Sorry cannot copy-paste the code…

Another simple and accurate solution. Complete gist here

 public class BaseLifeCycleCallbacks implements Application.ActivityLifecycleCallbacks { HashMap activities; BaseLifeCycleCallbacks() { activities = new HashMap(); } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { } @Override public void onActivityStarted(Activity activity) { //map Activity unique class name with 1 on foreground activities.put(activity.getLocalClassName(), 1); applicationStatus(); } @Override public void onActivityResumed(Activity activity) { } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { //map Activity unique class name with 0 on foreground activities.put(activity.getLocalClassName(), 0); applicationStatus(); } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityDestroyed(Activity activity) { } /** * Check if any activity is in the foreground */ private boolean isBackGround() { for (String s : activities.keySet()) { if (activities.get(s) == 1) { return false; } } return true; } /** * Log application status. */ private void applicationStatus() { Log.d("ApplicationStatus", "Is application background" + isBackGround()); if (isBackGround()) { //Do something if the application is in background } } 

I would like to recommend you to use another way to do this.

I guess you want to show start up screen while the program is starting, if it is already running in backend, don’t show it.

Your application can continuously write current time to a specific file. While your application is starting, check the last timestamp, if current_time-last_time>the time range your specified for writing the latest time, it means your application is stopped, either killed by system or user himself.