Cómo detectar cuándo una aplicación de Android pasa al segundo plano y vuelve al primer plano

Intento escribir una aplicación que hace algo específico cuando vuelve a primer plano después de un período de tiempo. ¿Hay alguna manera de detectar cuándo una aplicación se envía al fondo o se pone en primer plano?

Los onPause() y onResume() cuando la aplicación vuelve al fondo y vuelve a estar en primer plano. Sin embargo, también se llaman cuando la aplicación se inicia por primera vez y antes de que se elimine. Puedes leer más en Actividad .

No hay un enfoque directo para obtener el estado de la aplicación en segundo plano o en primer plano, pero incluso yo he enfrentado este problema y he encontrado la solución con onWindowFocusChanged y onStop .

Para obtener más detalles, consulte aquí Android: solución para detectar cuándo una aplicación de Android pasa al segundo plano y vuelve al primer plano sin getRunningTasks o getRunningAppProcesses .

Así es como he logrado resolver esto. Funciona bajo la premisa de que el uso de una referencia de tiempo entre transiciones de actividades probablemente proporcionará evidencia adecuada de que una aplicación ha sido “atrasada” o no.

En primer lugar, he utilizado una instancia de aplicación android.app. (Llamémosla MyApplication) que tiene un Timer, un TimerTask, una constante para representar la cantidad máxima de milisegundos que la transición de una actividad a otra podría razonablemente tomarse (fui con un valor de 2s) y un booleano para indicar si la aplicación estaba “en segundo plano” o no:

 public class MyApplication extends Application { private Timer mActivityTransitionTimer; private TimerTask mActivityTransitionTimerTask; public boolean wasInBackground; private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000; ... 

La aplicación también proporciona dos métodos para iniciar y detener el temporizador / tarea:

 public void startActivityTransitionTimer() { this.mActivityTransitionTimer = new Timer(); this.mActivityTransitionTimerTask = new TimerTask() { public void run() { MyApplication.this.wasInBackground = true; } }; this.mActivityTransitionTimer.schedule(mActivityTransitionTimerTask, MAX_ACTIVITY_TRANSITION_TIME_MS); } public void stopActivityTransitionTimer() { if (this.mActivityTransitionTimerTask != null) { this.mActivityTransitionTimerTask.cancel(); } if (this.mActivityTransitionTimer != null) { this.mActivityTransitionTimer.cancel(); } this.wasInBackground = false; } 

La última parte de esta solución es agregar una llamada a cada uno de estos métodos desde los eventos onResume () y onPause () de todas las actividades o, preferiblemente, en una Actividad base de la cual heredan todas sus Actividades concretas:

 @Override public void onResume() { super.onResume(); MyApplication myApp = (MyApplication)this.getApplication(); if (myApp.wasInBackground) { //Do specific came-here-from-background code } myApp.stopActivityTransitionTimer(); } @Override public void onPause() { super.onPause(); ((MyApplication)this.getApplication()).startActivityTransitionTimer(); } 

Entonces, en el caso de que el usuario simplemente esté navegando entre las actividades de su aplicación, onPause () de la actividad de salida inicia el temporizador, pero casi inmediatamente la nueva actividad que se ingresa cancela el temporizador antes de que pueda alcanzar el tiempo máximo de transición. Y entonces wasInBackground sería falso .

Por otro lado, cuando una actividad aparece en primer plano desde el Iniciador, el dispositivo se activa, finaliza la llamada, etc., es más que probable que la tarea del temporizador se haya ejecutado antes de este evento y, por lo tanto, wasInBackground se estableció en verdadero .

2018: Android lo admite de forma nativa mediante componentes del ciclo de vida.

Marzo de 2018 ACTUALIZACIÓN : ahora hay una mejor solución. Ver ProcessLifecycleOwner . Tendrá que usar los nuevos componentes de architecture 1.1.0 (más reciente en este momento) pero está específicamente diseñado para hacer esto.

Hay una muestra simple en esta respuesta, pero escribí una aplicación de muestra y una publicación de blog sobre ella.

Desde que escribí esto en 2014, surgieron diferentes soluciones. Algunos funcionaron, algunos se pensó que funcionaban , pero tenían fallas (¡incluida la mía!) Y nosotros, como comunidad (Android) aprendimos a vivir con las consecuencias y escribimos soluciones para los casos especiales.

Nunca suponga que un solo fragmento de código es la solución que está buscando, es poco probable el caso; Mejor aún, intente comprender lo que hace y por qué lo hace.

La clase MemoryBoss nunca fue utilizada por mí tal como está escrita aquí, era solo una pieza de pseudo código que funcionó.

A menos que exista un motivo válido para no utilizar los nuevos componentes de architecture (y hay algunos, especialmente si se dirige a super old apis), siga adelante y úselos. Están lejos de ser perfectos, pero tampoco lo eran ComponentCallbacks2 .

ACTUALIZACIÓN / NOTAS (noviembre de 2015) : La gente ha estado haciendo dos comentarios, el primero es que >= debe usarse en lugar de == porque la documentación indica que no debe verificar los valores exactos . Esto está bien para la mayoría de los casos, pero tenga en cuenta que si solo desea hacer algo cuando la aplicación se quedó en segundo plano, deberá usar == y también combinarlo con otra solución (como devoluciones de llamadas del ciclo de vida de la actividad), o puede no obtener su efecto deseado. El ejemplo (y esto me pasó a mí) es que si desea bloquear su aplicación con una pantalla de contraseña cuando se va al fondo (como 1Password si está familiarizado con ella), puede bloquear accidentalmente su aplicación si se agota. en la memoria y de repente están probando para >= TRIM_MEMORY , porque Android activará una llamada LOW MEMORY y será más alta que la suya. Así que ten cuidado cómo / qué pruebas.

Además, algunas personas han preguntado cómo detectar cuando regrese.

La forma más simple en que puedo pensar se explica a continuación, pero como algunas personas no están familiarizadas con ella, estoy agregando un pseudo código aquí. Asumiendo que tiene YourApplication y las clases MemoryBoss , en su class BaseActivity extends Activity (tendrá que crear una si no tiene una).

 @Override protected void onStart() { super.onStart(); if (mApplication.wasInBackground()) { // HERE YOU CALL THE CODE YOU WANT TO HAPPEN ONLY ONCE WHEN YOUR APP WAS RESUMED FROM BACKGROUND mApplication.setWasInBackground(false); } } 

Recomiendo onStart porque Dialogs puede detener una actividad, así que apuesto a que no quieres que tu aplicación piense que “se pasó al segundo plano” si todo lo que hiciste fue mostrar un cuadro de diálogo de pantalla completa, pero tu kilometraje puede variar.

Y eso es todo. El código en el bloque if solo se ejecutará una vez , incluso si va a otra actividad, el nuevo (que también extends BaseActivity ) informará que wasInBackground es false por lo que no ejecutará el código, hasta que se onMemoryTrimmed y la bandera está configurado a verdadero de nuevo .

Espero que ayude.

ACTUALIZACIÓN / NOTAS (abril de 2015) : antes de ir a Copiar y Pegar en este código, tenga en cuenta que he encontrado algunos casos en los que puede no ser 100% confiable y debe combinarse con otros métodos para lograr los mejores resultados. Cabe destacar que hay dos instancias conocidas en las que no se garantiza que se ejecute la llamada a la llamada onTrimMemory :

  1. Si su teléfono bloquea la pantalla mientras su aplicación está visible (digamos que su dispositivo se bloquea después de nn minutos), esta callback no se llama (o no siempre) porque la pantalla de locking está arriba, pero su aplicación todavía está “ejecutándose” aunque esté cubierta.

  2. Si su dispositivo tiene una memoria relativamente baja (y bajo tensión de memoria), el sistema operativo parece ignorar esta llamada e ir directamente a niveles más críticos.

Ahora, dependiendo de lo importante que es para usted saber cuándo su aplicación pasó a segundo plano, puede o no necesitar extender esta solución junto con el seguimiento del ciclo de vida de la actividad y otras cosas.

Solo tenga en cuenta lo anterior y tenga un buen equipo de QA;)

FIN DE ACTUALIZACIÓN

Puede ser tarde, pero hay un método confiable en Ice Cream Sandwich (API 14) y superiores .

Resulta que cuando su aplicación no tiene más UI visible, se activa una callback. La callback, que puede implementar en una clase personalizada, se llama ComponentCallbacks2 (sí, con dos). Esta callback solo está disponible en API Nivel 14 (Ice Cream Sandwich) y superior.

Básicamente, recibe una llamada al método:

 public abstract void onTrimMemory (int level) 

El nivel es 20 o más específicamente

 public static final int TRIM_MEMORY_UI_HIDDEN 

He estado probando esto y siempre funciona, porque el nivel 20 es solo una “sugerencia” de que es posible que desee liberar algunos recursos ya que su aplicación ya no es visible.

Para citar los documentos oficiales:

Level para onTrimMemory (int): el proceso mostraba una interfaz de usuario y ya no lo hace. Las grandes asignaciones con la IU deberían liberarse en este punto para permitir una mejor administración de la memoria.

Por supuesto, debe implementar esto para realmente hacer lo que dice (purgar la memoria que no se ha utilizado en cierto tiempo, borrar algunas colecciones que han estado sin usar, etc. Las posibilidades son infinitas (ver los documentos oficiales para otros posibles más) niveles críticos ).

Pero, lo interesante, es que el sistema operativo te está diciendo: HEY, tu aplicación pasó a segundo plano.

Que es exactamente lo que querías saber en primer lugar.

¿Cómo determinas cuándo regresaste?

Bueno, eso es fácil, estoy seguro de que tienes una “BaseActivity” para que puedas usar tu onResume () para marcar el hecho de que estás de vuelta. Debido a que la única vez que dirá que no ha regresado es cuando realmente recibe una llamada al método anterior onTrimMemory .

Funciona. No obtienes falsos positivos. Si se reanuda una actividad, estás de vuelta, el 100% de las veces. Si el usuario vuelve a la parte posterior, obtiene otra llamada onTrimMemory() .

Necesita suscribir sus actividades (o mejor aún, una clase personalizada).

La forma más fácil de garantizar que siempre reciba esto es crear una clase simple como esta:

 public class MemoryBoss 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) { // We're in the Background } // you might as well implement some memory cleanup here and be a nice Android dev. } } 

Para usar esto, en su implementación de la Aplicación ( ¿tiene una, DERECHA? ), Haga algo como:

 MemoryBoss mMemoryBoss; @Override public void onCreate() { super.onCreate(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { mMemoryBoss = new MemoryBoss(); registerComponentCallbacks(mMemoryBoss); } } 

Si creas una Interface puedes agregar un else a eso e implementar ComponentCallbacks (sin los 2) utilizado en cualquier elemento por debajo de API 14. Esa callback solo tiene el método onLowMemory() y no se llama cuando pasas al fondo , pero deberías usarlo para recortar la memoria.

Ahora inicie su aplicación y presione home. onTrimMemory(final int level) su onTrimMemory(final int level) (sugerencia: agregar registro).

El último paso es anular el registro de la callback. Probablemente, el mejor lugar sea el método onTerminate() de su aplicación, pero ese método no se onTerminate() en un dispositivo real:

 /** * This method is for use in emulated process environments. It will * never be called on a production Android device, where processes are * removed by simply killing them; no user code (including this callback) * is executed when doing so. */ 

Entonces, a menos que realmente tenga una situación en la que ya no desee estar registrado, puede ignorarlo, ya que su proceso se está muriendo a nivel de sistema operativo de todos modos.

Si decide cancelar el registro en algún momento (si, por ejemplo, proporciona un mecanismo de apagado para que su aplicación se limpie y muera), puede hacer lo siguiente:

 unregisterComponentCallbacks(mMemoryBoss); 

Y eso es.

Editar: los nuevos componentes de architecture trajeron algo prometedor: ProcessLifecycleOwner , vea la respuesta de @ vokilam


La solución real según una conversación de Google I / O :

 class YourApplication : Application() { override fun onCreate() { super.onCreate() registerActivityLifecycleCallbacks(AppLifecycleTracker()) } } class AppLifecycleTracker : Application.ActivityLifecycleCallbacks { private var numStarted = 0 override fun onActivityStarted(activity: Activity?) { if (numStarted == 0) { // app went to foreground } numStarted++ } override fun onActivityStopped(activity: Activity?) { numStarted-- if (numStarted == 0) { // app went to background } } } 

Sí. Sé que es difícil de creer que esta simple solución funcione, ya que tenemos muchas soluciones raras aquí.

Pero hay esperanza.

Basado en la respuesta de Martín Marconcinis (¡gracias!) Finalmente encontré una solución confiable (y muy simple).

 public class ApplicationLifecycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 { private static final String TAG = ApplicationLifecycleHandler.class.getSimpleName(); private static boolean isInBackground = false; @Override public void onActivityCreated(Activity activity, Bundle bundle) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityResumed(Activity activity) { if(isInBackground){ Log.d(TAG, "app went to foreground"); isInBackground = false; } } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } @Override public void onActivityDestroyed(Activity activity) { } @Override public void onConfigurationChanged(Configuration configuration) { } @Override public void onLowMemory() { } @Override public void onTrimMemory(int i) { if(i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){ Log.d(TAG, "app went to background"); isInBackground = true; } } } 

A continuación, agregue esto a su onCreate () de su clase de aplicación

 public class MyApp extends android.app.Application { @Override public void onCreate() { super.onCreate(); ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler(); registerActivityLifecycleCallbacks(handler); registerComponentCallbacks(handler); } } 

Usamos este método. Parece demasiado simple para trabajar, pero fue probado en nuestra aplicación y de hecho funciona sorprendentemente bien en todos los casos, incluyendo ir a la pantalla de inicio con el botón “inicio”, con el botón “regresar” o después del locking de pantalla. Darle una oportunidad.

La idea es que, cuando está en primer plano, Android siempre comienza una nueva actividad justo antes de detener la anterior. Eso no está garantizado, pero así es como funciona. Por cierto, Flurry parece usar la misma lógica (solo una conjetura, no lo compruebo, pero se engancha en los mismos eventos).

 public abstract class BaseActivity extends Activity { private static int sessionDepth = 0; @Override protected void onStart() { super.onStart(); sessionDepth++; if(sessionDepth == 1){ //app came to foreground; } } @Override protected void onStop() { super.onStop(); if (sessionDepth > 0) sessionDepth--; if (sessionDepth == 0) { // app went to background } } } 

Editar: según los comentarios, también pasamos a onStart () en versiones posteriores del código. Además, estoy agregando super llamadas, que faltaban en mi publicación inicial, porque esto era más un concepto que un código de trabajo.

Si su aplicación consiste en múltiples actividades y / o actividades astackdas como un widget de barra de tabs, entonces anular onPause () y onResume () no funcionará. Es decir, al comenzar una nueva actividad, las actividades actuales se detendrán antes de que se cree la nueva. Lo mismo aplica al terminar (usando el botón “Atrás”) una actividad.

He encontrado dos métodos que parecen funcionar como se desea.

El primero requiere el permiso GET_TASKS y consiste en un método simple que comprueba si la actividad superior del dispositivo pertenece a la aplicación, comparando los nombres de los paquetes:

 private boolean isApplicationBroughtToBackground() { ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List tasks = am.getRunningTasks(1); if (!tasks.isEmpty()) { ComponentName topActivity = tasks.get(0).topActivity; if (!topActivity.getPackageName().equals(context.getPackageName())) { return true; } } return false; } 

Este método se encontró en el marco Droid-Fu (ahora llamado Ignition).

El segundo método que implementé no requiere el permiso GET_TASKS, que es bueno. En cambio, es un poco más complicado de implementar.

En tu clase MainApplication tienes una variable que rastrea el número de actividades en ejecución en tu aplicación. En onResume () para cada actividad aumenta la variable y en onPause () la disminuye.

Cuando el número de actividades en ejecución llega a 0, la aplicación se pone en segundo plano SI las siguientes condiciones son verdaderas:

  • La actividad que se está pausando no se está terminando (se utilizó el botón “Atrás”). Esto se puede hacer utilizando el método activity.isFinishing ()
  • Una nueva actividad (el mismo nombre de paquete) no se está iniciando. Puede anular el método startActivity () para establecer una variable que lo indique y luego restablecerlo en onPostResume (), que es el último método que se ejecutará cuando se crea / reanuda una actividad.

Cuando puede detectar que la aplicación ha renunciado al fondo, es fácil detectar cuándo se vuelve a poner en primer plano también.

ProcessLifecycleOwner parece ser una solución prometedora también.

ProcessLifecycleOwner enviará ON_START , ON_RESUME eventos, ya que una primera actividad se mueve a través de estos eventos. ON_PAUSE , ON_STOP , los eventos se enviarán con un retraso después de que una última actividad pasó a través de ellos. Este retraso es suficiente para garantizar que ProcessLifecycleOwner no envíe ningún evento si las actividades se destruyen y se vuelven a crear debido a un cambio de configuración.

Una implementación puede ser tan simple como

 public class AppLifecycleListener implements LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_START) public void onMoveToForeground() { // app moved to foreground } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) public void onMoveToBackground() { // app moved to background } } // register observer ProcessLifecycleOwner.get().getLifecycle().addObserver(new AppLifecycleListener()); 

De acuerdo con el código fuente, el valor de retardo actual es de 700ms .

Crea una clase que extienda la Application . Luego en él podemos usar su método de anulación, onTrimMemory() .

Para detectar si la aplicación pasó a segundo plano, utilizaremos:

  @Override public void onTrimMemory(final int level) { if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Works for Activity // Get called every-time when application went to background. } else if (level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { // Works for FragmentActivty } } 

Considere usar onUserLeaveHint. Esto solo se invocará cuando tu aplicación quede en segundo plano. onPause tendrá casos de esquina para manejar, ya que se puede llamar por otros motivos; por ejemplo, si el usuario abre otra actividad en su aplicación, como su página de configuración, se invocará el método onPause de su actividad principal, aunque todavía estén en su aplicación; rastrear lo que está entrando dará lugar a errores cuando en su lugar simplemente puede usar la callback onUserLeaveHint, que hace lo que está pidiendo.

Cuando se llama a UserLeaveHint, puede establecer un indicador boolean inBackground en verdadero. Cuando se llama onResume, solo suponga que volvió al primer plano si se establece el indicador inBackground. Esto se debe a que onResume también se invocará en su actividad principal si el usuario estaba solo en el menú de configuración y nunca abandonó la aplicación.

Recuerde que si el usuario pulsa el botón de inicio mientras está en la pantalla de configuración, se invocará a UserLeaveHint en la actividad de configuración y cuando vuelva a aparecer se invocará a la función en la actividad de configuración. Si solo tiene este código de detección en su actividad principal, perderá este caso de uso. Para tener este código en todas sus actividades sin duplicar el código, tenga una clase de actividad abstracta que amplíe la Actividad, y coloque su código común en ella. Entonces cada actividad que tienes puede extender esta actividad abstracta.

Por ejemplo:

 public abstract AbstractActivity extends Activity { private static boolean inBackground = false; @Override public void onResume() { if (inBackground) { // You just came from the background inBackground = false; } else { // You just returned from another activity within your own app } } @Override public void onUserLeaveHint() { inBackground = true; } } public abstract MainActivity extends AbstractActivity { ... } public abstract SettingsActivity extends AbstractActivity { ... } 

ActivityLifecycleCallbacks podría ser de interés, pero no está bien documentado.

Sin embargo, si llama a registerActivityLifecycleCallbacks (), debería poder obtener devoluciones de llamada cuando se crean, destruyen, etc. Puede invocar getComponentName () para la actividad.

En su aplicación, agregue la callback y verifique la actividad raíz de una manera como esta:

 @Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityStopped(Activity activity) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityResumed(Activity activity) { } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityDestroyed(Activity activity) { } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { if (activity.isTaskRoot() && !(activity instanceof YourSplashScreenActivity)) { Log.e(YourApp.TAG, "Reload defaults on restring from background."); loadDefaults(); } } }); } 

I have created a project on Github app-foreground-background-listen

Create a BaseActivity for all Activity in your application.

 public class BaseActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } public static boolean isAppInFg = false; public static boolean isScrInFg = false; public static boolean isChangeScrFg = false; @Override protected void onStart() { if (!isAppInFg) { isAppInFg = true; isChangeScrFg = false; onAppStart(); } else { isChangeScrFg = true; } isScrInFg = true; super.onStart(); } @Override protected void onStop() { super.onStop(); if (!isScrInFg || !isChangeScrFg) { isAppInFg = false; onAppPause(); } isScrInFg = false; } public void onAppStart() { // Remove this toast Toast.makeText(getApplicationContext(), "App in foreground", Toast.LENGTH_LONG).show(); // Your code } public void onAppPause() { // Remove this toast Toast.makeText(getApplicationContext(), "App in background", Toast.LENGTH_LONG).show(); // Your code } } 

Now use this BaseActivity as a super class of all your Activity like MainActivity extends BaseActivity and onAppStart will be called when you start your application and onAppPause() will be called when the application goes the background from any screen.

This is pretty easy with ProcessLifecycleOwner

Add these dependencies

 implementation "android.arch.lifecycle:extensions:$project.archLifecycleVersion" kapt "android.arch.lifecycle:compiler:$project.archLifecycleVersion" 

In Kotlin :

 class ForegroundBackgroundListener : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_START) fun startSomething() { Log.v("ProcessLog", "APP IS ON FOREGROUND") } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun stopSomething() { Log.v("ProcessLog", "APP IS IN BACKGROUND") } } 

Then in your base activity:

 override fun onCreate() { super.onCreate() ProcessLifecycleOwner.get() .lifecycle .addObserver( ForegroundBackgroundListener() .also { appObserver = it }) } 

See my article on this topic: https://medium.com/@egek92/how-to-actually-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48

I found a good method to detect application whether enter foreground or background. Here is my code . Espero que esto te ayude

 /** * Custom Application which can detect application state of whether it enter * background or enter foreground. * * @reference http://www.vardhan-justlikethat.blogspot.sg/2014/02/android-solution-to-detect-when-android.html */ public abstract class StatusApplication extends Application implements ActivityLifecycleCallbacks { public static final int STATE_UNKNOWN = 0x00; public static final int STATE_CREATED = 0x01; public static final int STATE_STARTED = 0x02; public static final int STATE_RESUMED = 0x03; public static final int STATE_PAUSED = 0x04; public static final int STATE_STOPPED = 0x05; public static final int STATE_DESTROYED = 0x06; private static final int FLAG_STATE_FOREGROUND = -1; private static final int FLAG_STATE_BACKGROUND = -2; private int mCurrentState = STATE_UNKNOWN; private int mStateFlag = FLAG_STATE_BACKGROUND; @Override public void onCreate() { super.onCreate(); mCurrentState = STATE_UNKNOWN; registerActivityLifecycleCallbacks(this); } @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { // mCurrentState = STATE_CREATED; } @Override public void onActivityStarted(Activity activity) { if (mCurrentState == STATE_UNKNOWN || mCurrentState == STATE_STOPPED) { if (mStateFlag == FLAG_STATE_BACKGROUND) { applicationWillEnterForeground(); mStateFlag = FLAG_STATE_FOREGROUND; } } mCurrentState = STATE_STARTED; } @Override public void onActivityResumed(Activity activity) { mCurrentState = STATE_RESUMED; } @Override public void onActivityPaused(Activity activity) { mCurrentState = STATE_PAUSED; } @Override public void onActivityStopped(Activity activity) { mCurrentState = STATE_STOPPED; } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityDestroyed(Activity activity) { mCurrentState = STATE_DESTROYED; } @Override public void onTrimMemory(int level) { super.onTrimMemory(level); if (mCurrentState == STATE_STOPPED && level >= TRIM_MEMORY_UI_HIDDEN) { if (mStateFlag == FLAG_STATE_FOREGROUND) { applicationDidEnterBackground(); mStateFlag = FLAG_STATE_BACKGROUND; } }else if (mCurrentState == STATE_DESTROYED && level >= TRIM_MEMORY_UI_HIDDEN) { if (mStateFlag == FLAG_STATE_FOREGROUND) { applicationDidDestroyed(); mStateFlag = FLAG_STATE_BACKGROUND; } } } /** * The method be called when the application been destroyed. But when the * device screen off,this method will not invoked. */ protected abstract void applicationDidDestroyed(); /** * The method be called when the application enter background. But when the * device screen off,this method will not invoked. */ protected abstract void applicationDidEnterBackground(); /** * The method be called when the application enter foreground. */ protected abstract void applicationWillEnterForeground(); 

}

Edit 2: What I’ve written below will not actually work. Google has rejected an app that includes a call to ActivityManager.getRunningTasks(). From the documentation , it is apparent that this API is for debugging and development purposes only. I’ll be updating this post as soon as I have time to update the GitHub project below with a new scheme that uses timers and is almost as good.

Edit 1: I’ve written up a blog post and created a simple GitHub repository to make this really easy.

The accepted and top rated answer are both not really the best approach. The top rated answer’s implementation of isApplicationBroughtToBackground() does not handle the situation where the Application’s main Activity is yielding to an Activity that is defined in the same Application, but it has a different Java package. I came up with a way to do this that will work in that case.

Call this in onPause(), and it will tell you if your application is going into the background because another application has started, or the user has pressed the home button.

 public static boolean isApplicationBroughtToBackground(final Activity activity) { ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE); List tasks = activityManager.getRunningTasks(1); // Check the top Activity against the list of Activities contained in the Application's package. if (!tasks.isEmpty()) { ComponentName topActivity = tasks.get(0).topActivity; try { PackageInfo pi = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES); for (ActivityInfo activityInfo : pi.activities) { if(topActivity.getClassName().equals(activityInfo.name)) { return false; } } } catch( PackageManager.NameNotFoundException e) { return false; // Never happens. } } return true; } 

Puedes usar:

protected void onRestart ()

To differ between new starts and restarts.

enter image description here

My solution was inspired by @d60402’s answer and also relies on a time-window, but not using the Timer :

 public abstract class BaseActivity extends ActionBarActivity { protected boolean wasInBackground = false; @Override protected void onStart() { super.onStart(); wasInBackground = getApp().isInBackground; getApp().isInBackground = false; getApp().lastForegroundTransition = System.currentTimeMillis(); } @Override protected void onStop() { super.onStop(); if( 1500 < System.currentTimeMillis() - getApp().lastForegroundTransition ) getApp().isInBackground = true; } protected SingletonApplication getApp(){ return (SingletonApplication)getApplication(); } } 

where the SingletonApplication is an extension of Application class:

 public class SingletonApplication extends Application { public boolean isInBackground = false; public long lastForegroundTransition = 0; } 

I was using this with Google Analytics EasyTracker, and it worked. It could be extended to do what you seek using a simple integer.

 public class MainApplication extends Application { int isAppBackgrounded = 0; @Override public void onCreate() { super.onCreate(); appBackgroundedDetector(); } private void appBackgroundedDetector() { registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle bundle) { } @Override public void onActivityStarted(Activity activity) { EasyTracker.getInstance(MainApplication.this).activityStart(activity); } @Override public void onActivityResumed(Activity activity) { isAppBackgrounded++; if (isAppBackgrounded > 0) { // Do something here } } @Override public void onActivityPaused(Activity activity) { isAppBackgrounded--; } @Override public void onActivityStopped(Activity activity) { EasyTracker.getInstance(MainApplication.this).activityStop(activity); } @Override public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } @Override public void onActivityDestroyed(Activity activity) { } }); } } 

i know its a little late but i think all these answers do have some problems while i did it like below and that works perfect.

create a activity life cycle callback like this:

  class ActivityLifeCycle implements ActivityLifecycleCallbacks{ @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { } @Override public void onActivityStarted(Activity activity) { } Activity lastActivity; @Override public void onActivityResumed(Activity activity) { //if (null == lastActivity || (activity != null && activity == lastActivity)) //use this condition instead if you want to be informed also when app has been killed or started for the first time if (activity != null && activity == lastActivity) { Toast.makeText(MyApp.this, "NOW!", Toast.LENGTH_LONG).show(); } lastActivity = activity; } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } @Override public void onActivityDestroyed(Activity activity) { } } 

and just register it on your application class like below:

 public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(new ActivityLifeCycle()); } 

This is the modified version of @d60402’s answer: https://stackoverflow.com/a/15573121/4747587

Do everything mentioned there. But instead of having a Base Activity and making that as a parent for every activity and the overriding the onResume() and onPause , do the below:

In your application class, add the line:

registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback);

This callback has all the activity lifecycle methods and you can now override onActivityResumed() and onActivityPaused() .

Take a look at this Gist: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b

What I did is make sure that all in-app activities are launched with startActivityForResult then checking if onActivityResult was called before onResume. If it wasn’t, it means we just returned from somewhere outside our app.

 boolean onActivityResultCalledBeforeOnResume; @Override public void startActivity(Intent intent) { startActivityForResult(intent, 0); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); onActivityResultCalledBeforeOnResume = true; } @Override protected void onResume() { super.onResume(); if (!onActivityResultCalledBeforeOnResume) { // here, app was brought to foreground } onActivityResultCalledBeforeOnResume = false; } 

This is my solution https://github.com/doridori/AndroidUtils/blob/master/App/src/main/java/com/doridori/lib/app/ActivityCounter.java

Basically involved counting the lifecycle methods for all Activity’s with a timer to catch cases where there is no activity currently in the foreground but the app is (ie on rotation)

Aquí está mi solución. Just register this ActivityLifecycleCallbacks in your main Application class. In the comments, I mention a user profile Activity edge case. That Activity is simply one with transparent edges.

 /** * This class used Activity lifecycle callbacks to determine when the application goes to the * background as well as when it is brought to the foreground. */ public class Foreground implements Application.ActivityLifecycleCallbacks { /** * How long to wait before checking onStart()/onStop() count to determine if the app has been * backgrounded. */ public static final long BACKGROUND_CHECK_DELAY_MS = 500; private static Foreground sInstance; private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); private boolean mIsForeground = false; private int mCount; public static void init(final Application application) { if (sInstance == null) { sInstance = new Foreground(); application.registerActivityLifecycleCallbacks(sInstance); } } public static Foreground getInstance() { return sInstance; } public boolean isForeground() { return mIsForeground; } public boolean isBackground() { return !mIsForeground; } @Override public void onActivityStarted(final Activity activity) { mCount++; // Remove posted Runnables so any Meteor disconnect is cancelled if the user comes back to // the app before it runs. mMainThreadHandler.removeCallbacksAndMessages(null); if (!mIsForeground) { mIsForeground = true; } } @Override public void onActivityStopped(final Activity activity) { mCount--; // A transparent Activity like community user profile won't stop the Activity that launched // it. If you launch another Activity from the user profile or hit the Android home button, // there are two onStops(). One for the user profile and one for its parent. Remove any // posted Runnables so we don't get two session ended events. mMainThreadHandler.removeCallbacksAndMessages(null); mMainThreadHandler.postDelayed(new Runnable() { @Override public void run() { if (mCount == 0) { mIsForeground = false; } } }, BACKGROUND_CHECK_DELAY_MS); } @Override public void onActivityCreated(final Activity activity, final Bundle savedInstanceState) { } @Override public void onActivityResumed(final Activity activity) { } @Override public void onActivityPaused(final Activity activity) { } @Override public void onActivitySaveInstanceState(final Activity activity, final Bundle outState) { } @Override public void onActivityDestroyed(final Activity activity) { } } 

My app needs to “reboot” after return from background – show a series of activities, according to client solicitations. After extensive search on how to manage the background/foreground transitions (treated very differently between iOS and Android), I crossed this question. Found very useful help here, specially from the most voted answer and the one flagged as correct. However, simply reinstantiate the root activity EVERY TIME the app enters foreground looked too annoying, when you think about UX. The solution that worked for me, and the one I think’s most adequated – based on the Youtube and Twitter apps functionality – was to combine the answers from @GirishNair and @d60402: Calling the timer when the app’s trimming memory, as follows:

 @Override public void onTrimMemory(int level) { if (stateOfLifeCycle.equals("Stop")) { startActivityTransitionTimer(); } super.onTrimMemory(level); } 

My Timer limit is set to 30 seconds – I’m thinking about increasing this a little.

 private final long MAX_ACTIVITY_TRANSITION_TIME = 30000; 

And when app goes into foreground, is relaunched, or the app’s destroyed, call the method to cancel timer.

On App extension:

 @Override public void onActivityCreated(Activity activity, Bundle arg1) { stopActivityTransitionTimer(); stateOfLifeCycle = "Create"; } @Override public void onActivityDestroyed(Activity activity) { stopActivityTransitionTimer(); stateOfLifeCycle = "Destroy"; } 

On the activity (preferably on a base activity, inherited by the others):

 @Override protected void onStart() { super.onStart(); if (App.wasInBackground) { stopActivityTransitionTimer(); } } 

In my case, when app goes foreground after the max time, a new task is created, so the stopActivityTransitionTimer() is called upon onActivityCreated() or onActivityDestroyed(), in the app extension class – turning unnecessary to call the method in an activity. Espero eso ayude.

How about this solution

 public class BaseActivity extends Activity { static String currentAct = ""; @Override protected void onStart() { super.onStart(); if (currentAct.equals("")) Toast.makeText(this, "Start", Toast.LENGTH_LONG).show(); currentAct = getLocalClassName(); } @Override protected void onStop() { super.onStop(); if (currentAct.equals(getLocalClassName())) { currentAct = ""; Toast.makeText(this, "Stop", Toast.LENGTH_LONG).show(); } } } 

All Activity need to extends BaseActivity.

When an activity call another (A->B) then currentAct is not equal getLocalClassName() because the onStart() of the second activity (B) is called before the onStop() of the first (A) ( https://developer.android.com/guide/components/activities.html#CoordinatingActivities ).

When the user press the home button or change between application will just call onStop() and then currentAct is equal getLocalClassName().

This appears to be one of the most complicated questions in Android since (as of this writing) Android doesn’t have iOS equivalents of applicationDidEnterBackground() or applicationWillEnterForeground() callbacks. I used an AppState Library that was put together by @jenzz .

[AppState is] a simple, reactive Android library based on RxJava that monitors app state changes. It notifies subscribers every time the app goes into background and comes back into foreground.

It turned out this is exactly what I needed, especially because my app had multiple activities so simply checking onStart() or onStop() on an activity wasn’t going to cut it.

First I added these dependencies to gradle:

 dependencies { compile 'com.jenzz.appstate:appstate:3.0.1' compile 'com.jenzz.appstate:adapter-rxjava2:3.0.1' } 

Then it was a simple matter of adding these lines to an appropriate place in your code:

 //Note that this uses RxJava 2.x adapter. Check the referenced github site for other ways of using observable Observable appState = RxAppStateMonitor.monitor(myApplication); //where myApplication is a subclass of android.app.Application appState.subscribe(new Consumer() { @Override public void accept(@io.reactivex.annotations.NonNull AppState appState) throws Exception { switch (appState) { case FOREGROUND: Log.i("info","App entered foreground"); break; case BACKGROUND: Log.i("info","App entered background"); break; } } }); 

Depending on how you subscribe to the observable, you may have to unsubscribe from it to avoid memory leaks. Again more info on the github page .

By using below code I’m able to get my app foreground or background state.

For more detail about it’s working, strong text click here

 import android.content.ComponentCallbacks2; import android.content.Context; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private Context context; private Toast toast; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = this; } private void showToast(String message) { //If toast is already showing cancel it if (toast != null) { toast.cancel(); } toast = Toast.makeText(context, message, Toast.LENGTH_SHORT); toast.show(); } @Override protected void onStart() { super.onStart(); showToast("App In Foreground"); } @Override public void onTrimMemory(int level) { super.onTrimMemory(level); if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { showToast("App In Background"); } } } 

Create class with name MyApp like below:

 public class MyApp implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 { private Context context; public void setContext(Context context) { this.context = context; } private boolean isInBackground = false; @Override public void onTrimMemory(final int level) { if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { isInBackground = true; Log.d("status = ","we are out"); } } @Override public void onActivityCreated(Activity activity, Bundle bundle) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityResumed(Activity activity) { if(isInBackground){ isInBackground = false; Log.d("status = ","we are in"); } } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } @Override public void onActivityDestroyed(Activity activity) { } @Override public void onConfigurationChanged(Configuration configuration) { } @Override public void onLowMemory() { } } 

Then, everywhere you want (better first activity launched in app), add the code below:

 MyApp myApp = new MyApp(); registerComponentCallbacks(myApp); getApplication().registerActivityLifecycleCallbacks(myApp); 

¡Hecho! Now when the app is in the background, we get log status : we are out and when we go in app, we get log status : we are out

You can achieve this easily with the help of ActivityLifecycleCallbacks and ComponentCallbacks2 something like below.

Create a class AppLifeCycleHandler implementing above said interfaces.

 package com.sample.app; import android.app.Activity; import android.app.Application; import android.content.ComponentCallbacks2; import android.content.res.Configuration; import android.os.Bundle; /** * Created by Naveen on 17/04/18 */ public class AppLifeCycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 { AppLifeCycleCallback appLifeCycleCallback; boolean appInForeground; public AppLifeCycleHandler(AppLifeCycleCallback appLifeCycleCallback) { this.appLifeCycleCallback = appLifeCycleCallback; } @Override public void onActivityResumed(Activity activity) { if (!appInForeground) { appInForeground = true; appLifeCycleCallback.onAppForeground(); } } @Override public void onTrimMemory(int i) { if (i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { appInForeground = false; appLifeCycleCallback.onAppBackground(); } } @Override public void onActivityCreated(Activity activity, Bundle bundle) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } @Override public void onActivityDestroyed(Activity activity) { } @Override public void onConfigurationChanged(Configuration configuration) { } @Override public void onLowMemory() { } interface AppLifeCycleCallback { void onAppBackground(); void onAppForeground(); } } 

In your class which extends Application implement AppLifeCycleCallback to get the callbacks when app switches between foreground and background. Something like below.

 public class BaseApplication extends Application implements AppLifeCycleHandler.AppLifeCycleCallback{ @Override public void onCreate() { super.onCreate(); AppLifeCycleHandler appLifeCycleHandler = new AppLifeCycleHandler(this); registerActivityLifecycleCallbacks(appLifeCycleHandler); registerComponentCallbacks(appLifeCycleHandler); } @Override public void onAppBackground() { Log.d("LifecycleEvent", "onAppBackground"); } @Override public void onAppForeground() { Log.d("LifecycleEvent", "onAppForeground"); } } 

Espero que esto ayude.

EDIT As an alternative you can now use Life cycle aware architecture component.