sobre sistema servicio segundo quitar plano permanentes otras notificaciones notificacion muestra mantener desactivar datos aplicaciones android

android - sistema - messenger se muestra sobre otras aplicaciones xiaomi



Comprobando si una aplicación de Android se está ejecutando en segundo plano (29)

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


NO UTILICE ESTA RESPUESTA

La respuesta de user1269737 es la forma correcta (aprobada por Google / Android) de hacer esto . Ve a leer su respuesta y dales un +1.

Dejaré aquí mi respuesta original por la posteridad. Este fue el mejor disponible en 2012, pero ahora Android tiene el soporte adecuado para esto.

Respuesta original

La clave es usar ActivityLifecycleCallbacks (tenga en cuenta que esto requiere el nivel 14 de Android (Android 4.0)). Simplemente verifique si el número de actividades detenidas es igual al número de actividades iniciadas. Si son iguales, tu solicitud está siendo procesada. Si hay más actividades iniciadas, su aplicación aún está visible. Si hay más actividades reanudadas que en pausa, su aplicación no solo es visible, sino que también está en primer plano. Hay 3 estados principales en los que puede estar su actividad, entonces: 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 asíncronos que tiene getRunningTasks() , pero tampoco tiene que modificar todas las Activity en su aplicación para configurar / onResumed() algo en onResumed() / onPaused() . Son solo unas pocas líneas de código que son independientes y funcionan en toda su aplicación. Además, tampoco se requieren permisos funky.

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 // <application android:name="your.package.MyApplication" ... public class MyApplication extends Application { @Override public void onCreate() { // Simply add the handler, and that''s it! No need to add any code // to every activity. Everything is contained in MyLifecycleHandler // with just a few lines of code. Now *that''s* nice. registerActivityLifecycleCallbacks(new MyLifecycleHandler()); } }

@Mewzer 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; ¿Eso es un problema aquí?

No. Los documentos para onStop() dicen:

Tenga en cuenta que este método nunca se puede llamar, en situaciones de poca memoria donde el sistema no tiene suficiente memoria para mantener el proceso de su actividad en ejecución después de que se llame a su método onPause ().

La clave aquí es "mantener en ejecución el proceso de su actividad ..." Si alguna vez se alcanza esta situación de poca memoria, su proceso realmente se cancela (no solo su actividad). Esto significa que este método de verificación de antecedentes aún es válido porque a) no puede verificar los fondos de todos modos si su proceso se interrumpe, 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 .

¿Esto funciona para cambios de configuración?

Por defecto, no. configChanges=orientation|screensize establecer explícitamente configChanges=orientation|screensize ( | con cualquier otra cosa que desee) en su archivo de manifiesto y manejar los cambios de configuración, o 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 cuando se cambia entre las dos, que es cómo funciona este método de detección de antecedentes). Para configChanges esto, debe configurar configChanges para que su actividad no se destruya. Afortunadamente, tuve que configurar configChanges en todos mis proyectos porque no era deseable que toda mi actividad se destruyera en la rotación de la pantalla / el tamaño, por lo que nunca encontré que esto sea problemático. (¡Gracias a dpimka por refrescar mi memoria en esto y corregirme!)

Una nota:

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

Es importante saber que Android tiene un extraño momento de limbo al cambiar de actividades donde nada está en primer plano . Por esta razón, si verifica si su aplicación está en primer plano al cambiar de actividad (en la misma aplicación), se le informará que no está en primer plano (aunque su aplicación sigue siendo la aplicación 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 está visible (es decir, si no está en segundo plano) en el método super.onStop() su Activity después de super.onStop() .


A cuestas de lo que han dicho CommonsWare y Key, tal vez podría extender la clase de Aplicación y hacer que todas sus 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 explicarnos exactamente lo que tienes en mente? Cuando dice que se está ejecutando en segundo plano, ¿quiere decir que su aplicación aún está en la memoria aunque no esté en la pantalla? ¿Ha considerado el uso de los Servicios como una forma más persistente de administrar su aplicación cuando no está enfocada?


Basándose en la respuesta de @Cornstalks 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 alguna acción sobre el cambio de visibilidad y // tomar alguna acción sobre el cambio 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; } }


Desde la API 16 de Android, hay una forma sencilla de comprobar 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 como para usarlo cuando su servicio recibe una actualización del servidor y debe decidir si desea mostrar la notificación o no (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;


Hay algunas formas de detectar si la 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 )
    Realice un seguimiento de la visibilidad de su aplicación utilizando 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
    Implemente una clase de Application personalizada (tenga en cuenta el método estático isActivityVisible() ):

    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 :

    <application android:name="your.app.package.MyApplication" android:icon="@drawable/icon" android:label="@string/app_name" >

    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 se extiende desde MapActivity / ListActivity etc., aún necesita 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 el nivel de API 14 (Android 4.0). Puede usarlos para hacer un seguimiento de si una actividad de su aplicación es actualmente visible para el usuario. Compruebe la respuesta de Cornstalks a continuación para conocer los detalles.

  2. El equivocado
    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 RunningAppProcessInfo.IMPORTANCE_FOREGROUND si es igual a RunningAppProcessInfo.IMPORTANCE_FOREGROUND mientras RunningAppProcessInfo.processName es igual al nombre del paquete de su aplicación.

    Además, si llama a ActivityManager.getRunningAppProcesses() desde el subproceso de la interfaz de usuario de la aplicación, devolverá la importancia IMPORTANCE_FOREGROUND para su tarea, sin importar si está realmente en primer plano o no. Llámelo 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 encarecidamente que no la use. Y he aquí 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 mostrar al usuario las aplicaciones en ejecución, un administrador de tareas o algo similar.

    Sí, hay una lista guardada en la memoria de estas cosas. Sin embargo, está desactivado en otro proceso, administrado por subprocesos que se ejecutan por separado del suyo, y no es algo con lo que pueda contar (a) a tiempo para tomar la decisión correcta o (b) tener una imagen coherente para cuando regrese. Además, la decisión sobre a qué actividad de la "próxima" ir siempre se hace en el punto donde se producirá el cambio, y no es hasta ese punto exacto (donde el estado de la actividad se bloquea brevemente para hacer el cambio). En realidad sabemos a ciencia cierta cuál será la próxima cosa.

    Y no se garantiza que la implementación y el comportamiento global aquí sigan siendo los mismos 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 equivocada
    Droid-Fu biblioteca Droid-Fu mencionada en una de las respuestas utiliza ActivityManager.getRunningTasks para su método isApplicationBroughtToBackground . Vea el comentario de Dianne arriba y tampoco use ese método.


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

Segundo, 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); } }

Cuarto, todas las clases que se extienden desde SherlockActivity, reemplazé 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 programados en la implementación de la interfaz realizada en MyApplication.


La mejor solución que he encontrado utiliza temporizadores.

Ha iniciado un temporizador en onPause () y cancelado el mismo temporizador en onResume (), hay 1 instancia del temporizador (generalmente definido en la clase de aplicación). El temporizador en sí está configurado para ejecutar un Runnable después de 2 segundos (o el intervalo que crea que sea apropiado), cuando el temporizador se dispara, establece un indicador que marca la aplicación como en segundo plano.

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 pila trasera 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 simplemente puede activar un evento y varias partes de su aplicación pueden responder en consecuencia.


La respuesta de Idolón es propensa a errores y mucho más complicada, aunque se repite aquí. ¿ Verifica 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 BaseActivity que todas las Actividades extienden:

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

Cuando necesite verificar si alguna de las actividades de su aplicación está en primer plano, simplemente verifique isVisible() ;

Para entender este enfoque, marque esta respuesta del ciclo de vida de la actividad lado a lado : Actividad del ciclo de vida lado a lado


No hay manera, a no ser que usted lo rastree, para determinar si alguna de sus actividades es visible o no. Tal vez debería considerar hacer una nueva pregunta de , explicando qué es lo que está tratando de lograr a partir de la experiencia del usuario, por lo que quizás podamos darle ideas de implementación alternativas.


Probé la solución recomendada que utiliza ActivityLifecycleCallbacks y muchas otras, pero no funcionaron como se esperaba. Gracias a Sarge , se me ocurrió una solución bastante fácil 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 llamamos ActivityA.finish ), entonces se onStart() ActivityB antes de ActivityA onStop() .

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

Por lo tanto, en función del comportamiento del ciclo de vida de esta actividad, simplemente puede contar cuántas veces se onStart() en su programa onStart() y onPause() . Tenga en cuenta que para cada Activity de su programa, debe anular onStart() y onStop() , para onStop() / 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 extiende 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 utilizando 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 programa, deberíamos anular onStart() y onStop() y onStop() / 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 casos posibles:

  1. stateCounter = 0 : el número de detenidos es igual al número de actividades iniciadas, lo que significa que la aplicación se está ejecutando 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 está ejecutando en primer plano.

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

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


Puede usar ComponentCallbacks2 para detectar si la aplicación está en segundo plano. Por cierto, esta devolución de llamada solo está disponible en el nivel API 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 entonces 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 } } }


Si activa la configuración del desarrollador "No mantener actividades", no basta con verificar que solo el recuento de las actividades creadas. También debe comprobar isSaveInstanceState . Mi método personalizado isApplicationRunning () check es la aplicación de Android que 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) { } }


¿Qué hay de usar getApplicationState (). IsInForeground ()?


Documentos oficiales:

El sistema distingue entre aplicaciones de primer plano y de fondo. (La definición de fondo para fines de limitaciones del servicio es distinta de la definición utilizada por la administración de memoria; una aplicación puede estar en segundo plano en lo que respecta a la administración de memoria , pero en primer plano está relacionada con su capacidad para iniciar servicios). se considera que está en primer plano si se cumple alguna de las siguientes condiciones:

  1. Tiene una actividad visible, ya sea que la actividad se inicie o se detenga.
  2. Cuenta con un servicio de primer plano.
  3. Otra aplicación de primer plano está conectada a la aplicación, ya sea vinculando a uno de sus servicios o haciendo uso de uno de sus proveedores de contenido. Por ejemplo, la aplicación está en primer plano si otra aplicación se enlaza con:
    • YO ME
    • Servicio de papel tapiz
    • Oyente de notificaciones
    • Servicio de voz o texto.

Si ninguna de estas condiciones es verdadera, se considera que la aplicación está en segundo plano.


SOLUCIÓN DE GOOGLE - no es un hack, como 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'' } } }


En mi opinión, muchas respuestas introducen una gran cantidad de código y traen mucha complejidad y no legibilidad.

Cuando las personas preguntan sobre SO para comunicarse entre a Servicey a Activity, por lo general aconsejo usar LocalBroadcastManager .

¿Por qué?

Bueno, citando los documentos:

  • Sabe que los datos que está transmitiendo no abandonarán su aplicación, por lo que no debe preocuparse por filtrar datos privados.

  • No es posible que otras aplicaciones envíen estas transmisiones a su aplicación, por lo que no debe preocuparse por tener agujeros de seguridad que puedan explotar.

  • Es más eficiente que enviar una transmisión global a través del sistema.

No en la documentación:

  • No requiere bibliotecas externas.
  • El código es mínimo.
  • Es rápido de implementar y entender.
  • Sin patrón de devolución de llamadas / ultra-singleton / intra-proceso auto-implementado en absoluto ...
  • No hay referencias fuertes sobre Activity, Application, ...

Descripción

Por lo tanto, desea comprobar si alguno de los Activityestá actualmente en primer plano. Usualmente haces eso en una clase Serviceo en tu Applicationclase.

Esto significa que sus Activityobjetos se convierten en el remitente de una señal (estoy encendido / estoy fuera). Tu Service, por otro lado, se convierte en el Receiver.

Hay dos momentos en los que tu Activityte dice si va en primer plano o en segundo plano (sí, solo dos ... no 6).

Cuando el objeto Activityentra en primer plano, el onResume()método se activa (también se llama después onCreate()).

Cuando el Activityva en la espalda, onPause()se llama.

Estos son los momentos en los que Activitydebe enviar la señal a su Servicepara describir su estado.

En el caso de múltiples Activity, recuerde que Activityprimero entra en segundo plano y luego otro en primer plano.

Entonces la situación sería: *

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

El Service/ Applicationsimplemente seguirá escuchando esas señales y actuará en consecuencia.

Código (TLDR)

Tu Servicedebes implementar un BroadcastReceiverpara poder escuchar las señales.

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")

Registrate ReceiverenService::onCreate()

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

Des-registralo en Service::onDestroy()

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

Ahora Activitydebes comunicarte su estado.

En Activity::onResume()

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

En Activity::onPause()

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

Una situación muy, muy común.

Desarrollador: Quiero enviar datos desde mi Servicey actualizar el Activity. ¿Cómo verifico si Activityestá en primer plano?

Normalmente no hay necesidad de verificar si Activityestá en primer plano o no. Simplemente envíe los datos a través LocalBroadcastManagerde su Service. Si Activityestá encendido, entonces responderá y actuará.

Para esta situación muy común, el se Serviceconvierte en el remitente, y el Activityimplementa el BroadcastReceiver.

Por lo tanto, crear un Receiveren su Activity. Regístralo onResume()y anula el registro onPause(). No hay necesidad de usar los otros métodos del ciclo de vida .

Defina el Receivercomportamiento en onReceive()(actualice ListView, haga esto, haga eso, ...).

De esta manera Activity, solo escuchará si está en primer plano y no pasará nada si está en la parte posterior o si se destruye.

En caso de múltiples Activity, lo que Activityesté encendido responderá (si también implementan el Receiver).

Si todos están en segundo plano, nadie responderá y la señal simplemente se perderá.

Envíe los datos desde la Servicevía Intent(consulte el código anterior) especificando la identificación de la señal.


En mis actividades onResume y onPause escribo un booleano isVisible en SharedPrefences.

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

Y leerlo en otro lugar cuando sea necesario a través de,

// 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)){...}

Tal vez no sea elegante, pero me funciona ...


La única solución correcta:

MainActivity.java:

public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { MyApp.mainActivity = this; super.onCreate(savedInstanceState); ... }

MyApp.java:

public class MyApp extends Application implements LifecycleObserver { public static MainActivity mainActivity = null; @Override public void onCreate() { super.onCreate(); ProcessLifecycleOwner.get().getLifecycle().addObserver(this); } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) void onAppBackgrounded() { // app in background if (mainActivity != null) { ... } } @OnLifecycleEvent(Lifecycle.Event.ON_START) void onAppForegrounded() { // app in foreground if (mainActivity != null) { ... } } }


Me gustaría recomendarte que uses otra forma de hacer esto.

Supongo que desea mostrar la pantalla de inicio mientras se inicia el programa, si ya se está ejecutando en el backend, no lo muestre.

Su aplicación puede escribir continuamente la hora actual en un archivo específico. Mientras se inicia la aplicación, verifique la última marca de tiempo, si current_time-last_time> el intervalo de tiempo que especificó para escribir la última hora, esto significa que su aplicación está detenida, ya sea por el sistema o por el propio usuario.


Otra solución para este viejo post (para aquellos a los que podría ayudar):

<application android:name=".BaseApplication" ... >

public class BaseApplication extends Application { private class Status { public boolean isVisible = true; public boolean isFocused = true; } private Map<Activity, Status> activities; @Override public void onCreate() { activities = new HashMap<Activity, Status>(); 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(); } }


Ver el comentario en la función onActivityDestroyed.

Funciona con SDK target versión 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++; } }


Al iniciar la biblioteca de soporte versión 26 puede usar ProcessLifecycleOwner , solo agréguelo a su dependencia como se describe here , por ejemplo:

dependencies { def lifecycle_version = "1.1.1" // ViewModel and LiveData implementation "android.arch.lifecycle:extensions:$lifecycle_version" // alternatively - Lifecycles only (no ViewModel or LiveData). // Support library depends on this lightweight import implementation "android.arch.lifecycle:runtime:$lifecycle_version" annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" // use kapt for Kotlin }

Y luego solo consulta ProcessLifecycleOwnercuando quieras para el estado de la aplicación, ejemplos:

//Check if app is in background ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED; //Check if app is in foreground ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);



Creo que esta pregunta debería ser más clara. ¿Cuando? ¿Dónde? ¿Cuál es su situación específica que desea saber si su aplicación está en segundo plano?

Acabo de presentar mi solución a mi manera.
Hago esto utilizando el campo "importancia" de RunningAppProcessInfoclase en el onStopmétodo de cada actividad en mi aplicación, que puede lograrse simplemente proporcionando una BaseActivityextensión para otras actividades que implemente el onStopmétodo para verificar el valor de "importancia". Aquí está el código:

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


Debe usar una preferencia compartida para almacenar la propiedad y actuar sobre ella mediante el enlace de servicio de sus actividades. Si solo usa el enlace (que nunca usa el servicio de inicio), entonces su servicio se ejecutará solo cuando lo haga, (enlace onResume y desenlace onPause) que lo ejecutará solo en primer plano, y si desea trabajar fondo puede utilizar el servicio regular de parada de inicio.


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


Otra solución simple y precisa. Completa la esencia here

public class BaseLifeCycleCallbacks implements Application.ActivityLifecycleCallbacks { HashMap<String, Integer> activities; BaseLifeCycleCallbacks() { activities = new HashMap<String, Integer>(); } @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 } }


Puede que sea demasiado tarde para responder, pero si alguien viene de visita, aquí está la solución que sugiero. La razón (s) que quiere que una aplicación sepa que está en segundo plano o en primer plano puede ser muchas, algunas son, 1 Para mostrar brindis y notificaciones cuando el usuario está en BG. 2. Para realizar algunas tareas por primera vez, el usuario proviene de BG, como una encuesta, un redibujado, etc.

La solución de Idolon y otros se ocupa de la primera parte, pero no de la segunda. Si hay varias actividades en su aplicación, y el usuario está cambiando entre ellas, entonces, cuando esté en la segunda actividad, el indicador visible será falso. Por lo tanto, no se puede utilizar de manera determinista.

Hice algo de lo que fue sugerido por CommonsWare: "Si el Servicio determina que no hay actividades visibles, y permanece así por algún tiempo , detenga la transferencia de datos en el próximo punto de detención lógico".

La línea en negrita es importante y se puede utilizar para lograr el segundo elemento. Entonces, lo que hago es una vez que obtengo onActivityPaused (), no cambie lo visible a falso directamente, en vez de eso, tengo un temporizador de 3 segundos (que es el máximo para que se inicie la siguiente actividad), y si no hay onActivityResumed ) llame en los próximos 3 segundos, cambie visible a falso. De manera similar, en onActivityResumed () si hay un temporizador, lo cancelo. En resumen, lo visible se convierte en isAppInBackground.

Lo sentimos, no puede copiar y pegar el código ...