Estoy confundido aquí ... ¿por qué Android no puede proporcionar una anulación simple en la clase de aplicación para esto? ¿Es demasiado difícil saber esto a nivel de plataforma? @Override protegido vacío enApplicationSentToBackground () {}
Chuck D
2
@ChuckD: eso tendría sentido, que es lo que el SDK de Android parece evitar hacer a veces. : /
iOS tiene esto en picas, no estoy seguro de por qué Google lo hace tan difícil. Es una necesidad tan obvia.
Jerry Destremps
Respuestas:
388
Hay pocas formas de detectar si su aplicación se ejecuta en segundo plano, pero solo una de ellas es completamente confiable:
La solución correcta (créditos van a Dan , CommonsWare y NeTeInStEiN )
visibilidad de la pista de su aplicación por sí mismo utilizando Activity.onPause, Activity.onResumemétodos. Almacenar el estado de "visibilidad" en alguna otra clase. Las buenas opciones son su propia implementación de la Applicationo una Service(también hay algunas variaciones de esta solución si desea verificar la visibilidad de la actividad desde el servicio).
Ejemplo
Implementar Applicationclase personalizada (tenga en cuenta el isActivityVisible()método estático):
Agregue onPausey onResumea cada uno Activityen el proyecto (puede crear un antepasado común para sus Actividades si lo desea, pero si su actividad ya se ha extendido desde MapActivity/ ListActivityetc. aún debe escribir lo siguiente a mano):
Update ActivityLifecycleCallbacks se agregaron en el nivel 14 de API (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 obtener más detalles.
El incorrecto
solía sugerir la siguiente solución:
Puede detectar la aplicación actual en primer plano / fondo con la ActivityManager.getRunningAppProcesses()que devuelve una lista de RunningAppProcessInforegistros. Para determinar si su aplicación está en el RunningAppProcessInfo.importancecampo de verificación de primer plano para la igualdad RunningAppProcessInfo.IMPORTANCE_FOREGROUNDmientrasRunningAppProcessInfo.processName es igual al nombre del paquete de su aplicación.
Además, si llama ActivityManager.getRunningAppProcesses()desde el subproceso de interfaz de usuario de la aplicación, le devolverá importancia IMPORTANCE_FOREGROUNDpara su tarea, sin importar si realmente está en primer plano o no. Llámelo en el hilo de fondo (por ejemplo, vía 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 he aquí por qué. Como escribió Dianne Hackborn :
Estas API no están ahí para que las aplicaciones basen su flujo de interfaz de usuario, sino para hacer cosas como mostrarle al usuario las aplicaciones en ejecución, o un administrador de tareas, o tal.
Sí, hay una lista guardada en la memoria para 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) ver a tiempo para tomar la decisión correcta o (b) tener una imagen coherente para cuando regrese. Además, la decisión acerca de cuál es la "próxima" actividad a la que se debe ir siempre se realiza en el punto donde se realizará el cambio, y no es hasta ese punto exacto (donde el estado de la actividad se bloquea brevemente para hacer el cambio) De hecho, sepa con certeza 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.
Otra solución incorrecta que la biblioteca Droid-Fu mencionó en una de las respuestas utiliza ActivityManager.getRunningTaskspara su isApplicationBroughtToBackgroundmétodo. Vea el comentario de Dianne arriba y tampoco use ese método.
Para saber si presionó el botón de inicio o alguna otra aplicación se ha centrado: 1) implemente la buena solución . 2) En OnStopsolicitud de isActivityVisible.
Brais Gabin
28
Lamentablemente, su solución "correcta" no funciona para mí. Considere que recorre las actividades dentro de su aplicación. Lo que sucede entonces es que su bandera 'inForeground' es así: Verdadero, Falso (Entre la primera actividad en pausa y la segunda actividad en Reanudar), luego Verdadero nuevamente, etc. Luego necesitaría una histéresis de algún tipo.
Radu
14
Esta solución no funciona si no puede controlar directamente todas las actividades. Por ejemplo, si tiene una Actividad de un SDK de un tercero o incluso inicia una intención ACTION_VIEW.
user123321
66
Android es un desastre tan loco. ¿Nadie pensó que alguien podría querer persistir los datos de nivel de aplicación? Dame un respiro
8
Parece que la respuesta real a esta pregunta es "No puede verificarlo correctamente". La llamada solución 'correcta' es, en el mejor de los casos, una solución alternativa, también lo es usar ActivityLifecycleCallbacks. Aún debe considerar cambiar entre actividades que se registrarían como "no en primer plano". Me sorprende que no puedas comprobar una cosa tan simple como esa ...
Dejaré mi respuesta original aquí por el bien de la posteridad. Este fue el mejor disponible en 2012, pero ahora Android tiene el soporte adecuado para esto.
Respuesta original
La clave está usando ActivityLifecycleCallbacks(tenga en cuenta que esto requiere el nivel 14 de la API 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, su aplicación está en segundo plano. Si hay más actividades iniciadas, su aplicación aún está 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, entonces: visible y en primer plano, visible pero no en primer plano, y no visible y no en primer plano (es decir, en segundo plano).
Lo realmente bueno de este método es que no tiene los problemas asincrónicos getRunningTasks(), pero tampoco tiene que modificar cada uno Activityen su aplicación para configurar / desarmar algo en onResumed()/ onPaused(). Son solo unas pocas líneas de código que son independientes y funcionan en toda la aplicación. Además, tampoco se requieren permisos originales.
MyLifecycleHandler.java:
publicclassMyLifecycleHandlerimplementsActivityLifecycleCallbacks{// 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.privateint resumed;privateint paused;privateint started;privateint stopped;@Overridepublicvoid onActivityCreated(Activity activity,Bundle savedInstanceState){}@Overridepublicvoid onActivityDestroyed(Activity activity){}@Overridepublicvoid onActivityResumed(Activity activity){++resumed;}@Overridepublicvoid onActivityPaused(Activity activity){++paused;
android.util.Log.w("test","application is in foreground: "+(resumed > paused));}@Overridepublicvoid onActivitySaveInstanceState(Activity activity,Bundle outState){}@Overridepublicvoid onActivityStarted(Activity activity){++started;}@Overridepublicvoid 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" ...publicclassMyApplicationextendsApplication{@Overridepublicvoid 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(newMyLifecycleHandler());}}
@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; ¿Es eso un problema aquí?
No. Los documentos para onStop()decir:
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 ejecutándose después de que se llama a su método onPause ().
La clave aquí es "mantener el proceso de su actividad ejecutándose ..." Si alguna vez se llega a esta situación de poca memoria, su proceso se anula (no solo su actividad). Esto significa que este método de verificación de fondo sigue siendo válido porque a) no puede verificar el fondo de todos modos si su proceso se anula, yb) si su proceso comienza nuevamente (porque se crea una nueva actividad), el miembro las variables (ya sea estáticas o no) para MyLifecycleHandlerse restablecerán a 0.
¿Funciona esto para cambios de configuración?
Por defecto, no. Debe 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 su actividad será destruida y recreada. Si no se establece esto, los métodos de su actividad serán llamados en el orden siguiente: 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 cómo funciona este método de detección de fondo). Para evitar esto, debe configurarlo configChangespara que su actividad no se destruya. Afortunadamente, tuve que configurarconfigChangesYa en todos mis proyectos porque no era deseable que toda mi actividad se destruyera en la pantalla, gire / cambie el tamaño, por lo que nunca he encontrado 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 estar en primer plano (por ejemplo, si hay una superposición de notificaciones transparente). Es por eso que actualicé esta respuesta para reflejar eso.
Es importante saber que Android tiene un momento de limbo extraño al cambiar actividades donde nada está en primer plano . Por esta razón, si verifica si su aplicación está en primer plano al cambiar entre actividades (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 comprobar si su aplicación está en primer plano en su Activity's onPause()método despuéssuper.onPause() . Solo recuerda el extraño estado del limbo del que acabo de hablar.
Puede comprobar si su aplicación es visible (es decir, si no es en el fondo) en su Activity's onStop()método despuéssuper.onStop() .
Esto parece interesante, pero ¿qué sucede en situaciones de poca memoria? No se garantiza que se llamará a onStop (). ¿Podríamos entrar en la situación en la que no se llama a onStop () y el contador detenido no se incrementa, esto significa que la verificación de fondo ya no es confiable? ¿O esto nunca sucedería?
Mewzer
1
Además, ¿esto ignorará los cambios de configuración? ¿O la aplicación se considerará en segundo plano si una actividad se vuelve a crear como resultado de un cambio de configuración (por ejemplo, un cambio de orientación)? Lo siento, por las preguntas, pero creo que estás en algo y estoy interesado en saber si funciona en estos casos extremos.
Mewzer
1
@Mewzer: iba a responder como un comentario, pero me tomará un poco escribir para obtener estas respuestas, así que vuelva a consultar en unos minutos y editaré mi respuesta.
Tallo de maíz
1
@Mewzer: Deberías encontrar tus respuestas ahora. ¡Avíseme si hay alguna otra pregunta!
Tallo de maíz
2
@Mewzer: Acabo de agregar una nota en la que podría estar interesado. Específicamente, verifique los antecedentes onStop()después super.onStop(). No verifique el fondo en onPause().
Cornstalks
187
SOLUCIÓN DE GOOGLE : no es un truco, como las soluciones anteriores. Utilice ProcessLifecycleOwner
Kotlin:
classArchLifecycleApp: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}}
Java:
publicclassArchLifecycleAppextendsApplicationimplementsLifecycleObserver{@Overridepublicvoid onCreate(){super.onCreate();ProcessLifecycleOwner.get().getLifecycle().addObserver(this);}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)publicvoid onAppBackgrounded(){//App in background}@OnLifecycleEvent(Lifecycle.Event.ON_START)publicvoid onAppForegrounded(){// App in foreground}}
en app.gradle
dependencies {...
implementation "android.arch.lifecycle:extensions:1.1.0"//New Android X dependency is this -
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"}
allprojects {
repositories {...
google()
jcenter()
maven { url 'https://maven.google.com'}}}
¡Esta definitivamente debería ser la respuesta correcta! Funcionó de
maravilla
2
Esto funciona perfectamente, también modifiqué un poco para poder acceder al estado de primer plano / fondo más fácilmente fuera de esta clase: companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }entonces puedes obtener el estado de primer plano conArchLifecycleApp.isForeground()
Jose Jet
2
Oh hombre, esto es mucho mejor que mi vieja respuesta. Ten un +1 de mi parte. Actualicé mi respuesta para señalar a las personas la suya.
Cornstalks
2
Aunque esta es una respuesta correcta, no es necesario implementar devoluciones de llamada, solo puede consultar ProcessLifecycleOwner cuando lo desee. Compruebe stackoverflow.com/a/52678290/6600000
Keivan Esbati el
2
Como dice el documento The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes. , esto no funciona para las multiple processesaplicaciones, ¿hay alguna API que podamos lograr con elegancia?
acntwww
23
A partir de la versión 26 de la biblioteca de soporte, puede usar ProcessLifecycleOwner , simplemente agréguelo a su dependencia como se describe aquí , 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 el estado de la aplicación, ejemplos:
//Check if app is in backgroundProcessLifecycleOwner.get().getLifecycle().getCurrentState()==Lifecycle.State.CREATED;//Check if app is in foregroundProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
Gracias, esta es la forma mejor y más fácil que es adecuada en cualquier parte de tu código, especialmente cuando usas fcm.
Mihae Kheel
Si la aplicación se cierra por completo, ¿cuál sería el primer método?
Evgeniy Mishustin
@EvgeniyMishustin que depende del estado actual de la aplicación, pero por lo general verías CREADO y DESTRUIDO y después de eso, no recibirías ningún evento nuevo.
Keivan Esbati
Entonces, ¿dónde está cualquier declaración "IF" para ver si la aplicación IF está en segundo plano (primer plano)
Ekashking
@ekashking acaba de poner la declaración completa en la cláusula if. Por ejemplo: if (ProcessLifecycleOwner.get (). GetLifecycle (). GetCurrentState (). IsAtLeast (Lifecycle.State.STARTED)) => La aplicación está en primer plano
Keivan Esbati
20
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 como para usarlo cuando su servicio recibe actualizaciones del servidor y tiene que decidir si mostrar notificación o no (porque si la IU está en primer plano, el usuario notará la actualización sin notificación).
¿Debería estar este código dentro de la clase de servicio u otra clase, por ejemplo, la clase de aplicación? Muchas gracias.
Woppi el
... donde quiera que lo use, ya que la línea final es solo un booleano con el que comprobaría.
AO_
Esta es la misma metodología que AWS Android SDK para notificaciones push.
spakmad
Tenga en cuenta que "la definición de fondo para fines de limitaciones de servicio es distinta de la definición utilizada por la administración de memoria; una aplicación podría estar en segundo plano en lo que respecta a la administración de memoria, pero en primer plano en lo que respecta a su capacidad para iniciar servicios). " developer.android.com/about/versions/oreo/background.html (
ARLabs
Gracias, esto funcionó! Pude usar este código JobServicepara detectar que el servicio se está ejecutando en segundo plano.
Idolon's answer is error prone- desafortunadamente tengo que estar de acuerdo contigo. Según el comentario de Dianne Hackborn en los Grupos de Google, actualicé mi respuesta. Compruébalo por favor para los detalles.
Idolon
2
Esta tampoco es una solución infalible. Un escenario es si el usuario tira hacia abajo el panel de notificaciones, ni el onPause, onStopni el onResumeevento se llama. Entonces, ¿qué haces si ninguno de estos eventos se dispara?
Lamentablemente, pero este código funciona mal cuando se inicia una actividad cuando la pantalla está apagada. En este caso, onResume y onPause se llaman making isVisible = false.
CoolMind
@CoolMind ¿Puede explicar cuál es el caso de uso en el que iniciaría una actividad en segundo plano?
Neteinstein
11
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 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 a ActivityB desde ActivityA (y no a call ActivityA.finish), onStart()se llamará a ActivityB antes que ActivityA onStop().
Esa es también la principal diferencia entre onStop()y onPause()que ninguno mencionó en los artículos que leí.
Entonces, según el comportamiento del ciclo de vida de esta actividad, simplemente puede contar cuántas veces lo hizo onStart()y onPause()recibió llamadas en su programa. Tenga en cuenta que para cada unoActivity de sus programas, debe anularonStart() yonStop() , para aumentar / disminuir la variable estática utilizada para contar. A continuación se muestra el código que implementa esta lógica. Tenga en cuenta que estoy usando una clase que se extiende Application, así que no se olvide de declarar en la Manifest.xmletiqueta de la aplicación: android:name=".Utilities"aunque también se puede implementar usando una clase personalizada simple.
publicclassUtilitiesextendsApplication{privatestaticint stateCounter;publicvoid onCreate(){super.onCreate();
stateCounter =0;}/**
* @return true if application is on background
* */publicstaticboolean isApplicationOnBackground(){return stateCounter ==0;}//to be called on each Activity onStart()publicstaticvoid activityStarted(){
stateCounter++;}//to be called on each Activity onStop()publicstaticvoid activityStopped(){
stateCounter--;}}
Ahora en cada actividad de nuestro programa, debemos anular onStart() y onStop()e incremento / decremento como se muestra a continuación:
@Overridepublicvoid onStart(){super.onStart();Utilities.activityStarted();}@Overridepublicvoid 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:
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.
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 cual es imposible. Si encuentra este caso, significa que no está aumentando / disminuyendo el contador como debería.
Estás listo para partir Debería verificar si su aplicación está en segundo plano en el interior onStop().
Me muevo if(Utilities.isApplicationOnBackground()) …a Utilities. Porque de lo contrario, solo una actividad específica reaccionará al evento.
Nombre para mostrar
10
No hay forma, salvo que lo rastree usted mismo, para determinar si alguna de sus actividades es visible o no. Quizás debería considerar hacer una nueva pregunta de StackOverflow, explicando qué es lo que está tratando de lograr a partir de una experiencia de usuario, para que quizás podamos darle ideas de implementación alternativas.
En Android, tenemos una configuración llamada "Datos de fondo". Esta configuración desactiva cualquier conexión de datos en segundo plano cuando la aplicación se ejecuta en segundo plano. Quiero implementar la alternancia de "Datos de fondo" para mi aplicación, por lo que cuando ninguna de mis actividades sea visible para el usuario, me gustaría que mi servicio deje de transferir datos, pero en el momento en que se reanude una de mis actividades, me gustaría reanudar la transferencia de datos
cppdev
1
@cppdev: Con suerte, la "transferencia de datos" está siendo realizada por a Service. Si es así, haga que sus actividades notifiquen al servicio a medida que aparecen y desaparecen. Si Servicedetermina que no hay actividades visibles y permanece así durante cierto tiempo, detenga la transferencia de datos en el siguiente punto de detención lógico. Sí, esto requerirá un código para cada una de sus actividades, pero en este momento, eso es inevitable AFAIK.
CommonsWare
1
Si desea evitar copiar y pegar el código común entre todas sus actividades, puede crear una clase que MyActivityClassherede Activitye implemente los métodos del ciclo de vida, y haga que todas sus actividades hereden deMyActivityClass . Esto no hay trabajo para PreferenceActivityo MapActivityembargo (véase esta pregunta )
Guillaume Brunerie
@CommonsWare lo había intentado con OnPause () onResume () que está activo o no, pero si mi aplicación Ver dosen't en pantalla de la vista si se ejecuta en segundo plano cómo comprobar si está activo o no
Manoj
@CommonsWare lo había intentado con OnPause () onResume () que está activo o no, pero si mi aplicación Ver dosen't en pantalla de la vista si se ejecuta en segundo plano cómo comprobar si está activo o no
Manoj
5
Puede usar ComponentCallbacks2 para detectar si la aplicación está en segundo plano. Por cierto, esta devolución de llamada solo está disponible en API Nivel 14 (Ice Cream Sandwich) y superiores.
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 un activity, service, etc.
publicclassMainActivityextendsAppCompatActivityimplementsComponentCallbacks2{@Overridepublicvoid onConfigurationChanged(finalConfiguration newConfig){}@Overridepublicvoid onLowMemory(){}@Overridepublicvoid onTrimMemory(finalint level){if(level ==ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){// app is in background}}}
He intentado su respuesta pero no es tan confiable. la devolución de llamada onTrimMemory no se activará cuando la pantalla esté bloqueada ni al presionar el botón "encendido" para bloquear la pantalla. Tampoco siempre devolverá TRIM_MEMORY_UI_HIDDEN si su aplicación está visible y abre otra aplicación a través de una notificación de barra de estado. La única solución confiable es implementar ActivityLifecycleCallbacks y ajustarlo a los casos de uso.
Velval
4
A partir de la respuesta @Cornstalks se incluyen un par de funciones ú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 medida sobre el cambio de visibilidad y // tomar alguna medida sobre el cambio en primer plano)
La mejor solución que se me ocurrió utiliza temporizadores.
Ha iniciado un temporizador en onPause () y cancela el mismo temporizador en onResume (), hay 1 instancia del temporizador (generalmente definido en la clase Aplicación). El temporizador en sí está configurado para ejecutar un Runnable después de 2 segundos (o cualquier intervalo que considere apropiado), cuando se activa el temporizador, establece una bandera 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 posterior y no requiere ningún permiso para implementar.
Esta solución funciona bien si también usa un bus de eventos, ya que su temporizador simplemente puede disparar un evento y varias partes de su aplicación pueden responder en consecuencia.
Estoy empezando a pensar que esta es la mejor (aunque desafortunada) solución
dhaag23
Sí, esta es la mejor solución que he logrado también. Necesitaba detener el escaneo de bluetooth cuando la aplicación no estaba en primer plano, pero no podía simplemente usar onpause o detener o destruir porque no quería detener y comenzar constantemente cuando el usuario navegaba por la aplicación.
CaptRespect
3
Si activa la configuración del desarrollador "No mantener actividades", compruebe que solo el recuento de actividades creadas no es suficiente. Debe verificar también isSaveInstanceState . Mi método personalizado esAplicaciónRunning () es ejecutar la aplicación de Android:
No veo cómo esta solución puede darme una respuesta a una pregunta simple dentro de una declaración IF sobre mi actividad (o fragmento) si mi aplicación está en segundo plano o en primer plano. ¿Dónde está la declaración "SI"?
Ekashking
2
Para aprovechar lo que han dicho CommonsWare y Key, quizás podría extender la clase de aplicación y hacer que todas sus actividades llamen a eso en sus métodos onPause / onResume. Esto le permitiría saber qué Actividad (es) están visibles, pero esto probablemente podría manejarse mejor.
¿Puedes explicar exactamente lo que tienes en mente? Cuando dice que se ejecuta en segundo plano, ¿quiere decir simplemente que su aplicación aún está en la memoria aunque no esté actualmente en la pantalla? ¿Ha considerado usar los Servicios como una forma más persistente de administrar su aplicación cuando no está enfocada?
En Android, tenemos una configuración llamada "Datos de fondo". Esta configuración desactiva cualquier conexión de datos en segundo plano cuando la aplicación se ejecuta en segundo plano. Quiero implementar la alternancia de "Datos de fondo" para mi aplicación, por lo que cuando ninguna de mis actividades sea visible para el usuario, me gustaría que mi servicio deje de transferir datos, pero en el momento en que se reanude una de mis actividades, me gustaría reanudar la transferencia de datos
cppdev
1
Applicationno tiene onPause()o onResume().
CommonsWare
1
@CommonsWare Tienes razón, me refería a cada Actividad individual que contactaba a la Aplicación en su pausa / currículum. Esta es básicamente la idea que acaba de compartir en el comentario a su respuesta, aunque utilizó los Servicios, lo que me imagino que es un movimiento más inteligente.
Dan
2
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:
La actividad se detiene cuando aparece un cuadro de diálogo, por lo que todas las soluciones recomendadas son medias soluciones. También necesita crear ganchos para los diálogos.
El sistema distingue entre aplicaciones en primer plano y en segundo plano. (La definición de fondo para fines de limitaciones de 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 en lo que respecta a su capacidad para iniciar servicios). se considera que está en primer plano si se cumple alguna de las siguientes condiciones:
Tiene una actividad visible, ya sea que la actividad se inicie o se detenga.
Cuenta con un servicio de primer plano.
Otra aplicación en 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 une a su:
YO ME
Servicio de papel tapiz
Oyente de notificación
Servicio de voz o texto
Si ninguna de esas condiciones es verdadera, se considera que la aplicación está en segundo plano.
Debe usar una preferencia compartida para almacenar la propiedad y actuar sobre ella utilizando el enlace de servicio de sus actividades. Si usa solo el enlace, (eso nunca es usar startService), entonces su servicio se ejecutará solo cuando lo enlace, (bind onResume y unbind onPause) que haría que se ejecute solo en primer plano, y si desea trabajar en En segundo plano, puede utilizar el servicio regular de inicio y parada.
Creo que esta pregunta debería ser más clara. ¿Cuando? ¿Dónde? ¿Cuál es su situación específica que desea conocer si su aplicación está en segundo plano?
Acabo de presentar mi solución en mi camino.
Lo hago al usar el campo "importancia" de la RunningAppProcessInfoclase en el onStopmétodo de cada actividad en mi aplicación, lo que se puede lograr simplemente proporcionando una BaseActivityextensión para otras actividades que implementa el onStopmétodo para verificar el valor de "importancia". Aquí está el código:
Tengo alrededor de 10 actividades en mi aplicación. Entonces quiero saber si ninguno de ellos es visible para el usuario. En general, quiero saber si mi aplicación en su conjunto se está ejecutando en segundo plano
cppdev
Entonces haces un seguimiento de todos los 10-ish. O, como sugirió CommonsWare, explique lo que está tratando de hacer.
Clave del
3
Esto no es correcto Su actividad es visible hasta onStop; entre onPausey onStopes visible , pero no en primer plano .
nickgrim
@nickgrim: ¿qué no es correcto? Dije que una actividad ya no es visible después de que onStop()se llama, que está alineada con lo que escribió.
Clave
@Key: Originalmente dijiste hasta que onPausese llama: una edición reciente te ha corregido.
nickgrim
0
¿Qué pasa con el uso de getApplicationState (). IsInForeground ()?
En mi opinión, muchas respuestas introducen una gran carga de código y traen mucha complejidad y no legibilidad.
Cuando la gente pregunta sobre SO cómo comunicar entre una Servicey una Activity, por lo general consejos para utilizar la LocalBroadcastManager .
¿Por qué?
Bueno, citando los documentos:
Sabe que los datos que está transmitiendo no saldrán de su aplicación, por lo que no debe preocuparse por la pérdida de 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 los documentos:
No requiere bibliotecas externas.
El código es mínimo
Es rápido de implementar y comprender
No hay devoluciones de llamada auto-implementadas personalizadas / ultra-singleton / patrón intraproceso en absoluto ...
No hay referencias fuertes sobre Activity, Application, ...
Descripción
Por lo tanto, desea verificar si alguno de ellos Activityestá actualmente en primer plano. Usualmente haces eso en un Service, o tuApplication clase.
Esto significa que sus Activityobjetos se convierten en el emisor de una señal (estoy encendido / apagado). Tu Service, por otro lado, se convierte en elReceiver .
Hay dos momentos en que suActivity te dice si está en primer plano o en segundo plano (sí, solo dos ... no 6).
Cuando Activityentra en primer plano, onResume()se activa el método (también llamado después onCreate()).
Cuando Activityva en la parte de atrás, onPause()se llama.
Estos son los momentos en los que Activitydebe enviar la señal a suService para describir su estado.
En caso de múltiples Activity, recuerde elActivity pasa al fondo primero, luego otro entra en primer plano.
El Service/ Applicationsimplemente seguirá escuchando esas señales y actuará en consecuencia.
Código (TLDR)
Su Servicedebe implementar un BroadcastReceiverfin de escuchar señales.
this.localBroadcastReceiver =newBroadcastReceiver(){@Overridepublicvoid onReceive(Context context,Intent intent){// received data if Activity is on / off}}publicstaticfinalIntentFilter SIGNAL_FILTER =newIntentFilter("com.you.yourapp.MY_SIGNAL")
@Overrideprotectedvoid onDestroy(){// I'm dead, no need to listen to anything anymore.LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);}
Ahora tu Activitydebe comunicar su estado.
En Activity::onResume()
Intent intent =newIntent();
intent.setAction(SomeActivity.SIGNAL_FILTER);// put ON boolean in intent LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
En Activity::onPause()
Intent intent =newIntent();
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 el Activityestá en primer plano?
Por lo general, no es necesario verificar si Activityestá en primer plano o no. Simplemente envíe los datos a través LocalBroadcastManagerde su Service. Si Activityestá activado, responderá y actuará.
Para esta situación muy común, el se Serviceconvierte en el remitente y el Activityimplementa el BroadcastReceiver.
Entonces, crea un Receiveren tu Activity. Regístrese onResume()y anule el registro onPause(). No es necesario utilizar los otros métodos de 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 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 ID de la señal.
fun isAppInForeground():Boolean{
val activityManager = getSystemService(Context.ACTIVITY_SERVICE)asActivityManager?:returnfalse
val appProcesses = activityManager.runningAppProcesses ?:returnfalse
val packageName = packageName
for(appProcess in appProcesses){if(appProcess.importance ==ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName == packageName){returntrue}}returnfalse}
Ninguna de las respuestas se ajusta al caso específico si se busca saber si una actividad específica está en primer plano y si usted es un SDK sin acceso directo a la Aplicación. Para mí, estaba en el hilo de fondo después de recibir una notificación automática para un nuevo mensaje de chat y solo quería mostrar una notificación del sistema si la pantalla de chat no estaba en primer plano.
Usando ActivityLifecycleCallbackseso como se ha recomendado en otras respuestas, he creado una pequeña clase de utilidad que alberga la lógica de si MyActivityestá en primer plano o no.
classMyActivityMonitor(context:Context):Application.ActivityLifecycleCallbacks{privatevar isMyActivityInForeground =false
init {(context.applicationContext asApplication).registerActivityLifecycleCallbacks(this)}
fun isMyActivityForeground()= isMyActivityInForeground
override fun onActivityPaused(activity:Activity?){if(activity isMyActivity){
isMyActivityInForeground =false}}override fun onActivityResumed(activity:Activity?){if(activity isMyActivity){
isMyActivityInForeground =true}}
Y léalo 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 funciona para mí ...
Puede ser demasiado tarde para responder, pero si alguien viene de visita, entonces esta es la solución que sugiero. Para mostrar tostadas y notificaciones cuando el usuario está en BG. 2. Para realizar algunas tareas por primera vez, el usuario proviene de BG, como una encuesta, redibujar, etc.
La solución de Idolon y otros se encarga de la primera parte, pero no para la segunda. Si hay varias actividades en su aplicación, y el usuario está cambiando entre ellas, entonces cuando esté en la segunda actividad, la bandera visible será falsa. Por lo tanto, no se puede usar de manera determinista.
Hice algo que fue sugerido por CommonsWare, "Si el Servicio determina que no hay actividades visibles, y permanece así por un período de tiempo , detenga la transferencia de datos en el siguiente punto lógico de detención".
La línea en negrita es importante y se puede usar para lograr el segundo elemento. Entonces, lo que hago es que una vez que obtengo el onActivityPaused (), no cambie el visible a falso directamente, en su lugar tenga un temporizador de 3 segundos (ese es el máximo para que se inicie la próxima actividad), y si no hay onActivityResumed ( ) llame en los próximos 3 segundos, cambie visible a falso. Del mismo modo en onActivityResumed () si hay un temporizador, lo cancelo. En resumen, lo visible se convierte en isAppInBackground.
Lo sentimos, no puedo copiar y pegar el código ...
Me gustaría recomendarle que use 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 back-end, no lo muestre.
Su aplicación puede escribir continuamente la hora actual en un archivo específico. Mientras su aplicación se está iniciando, verifique la última marca de tiempo, si current_time-last_time> el rango de tiempo que especificó para escribir la última hora, significa que su aplicación se detiene, ya sea eliminada por el sistema o el propio usuario.
Respuestas:
Hay pocas formas de detectar si su aplicación se ejecuta en segundo plano, pero solo una de ellas es completamente confiable:
La solución correcta (créditos van a Dan , CommonsWare y NeTeInStEiN )
visibilidad de la pista de su aplicación por sí mismo utilizando
Activity.onPause
,Activity.onResume
métodos. Almacenar el estado de "visibilidad" en alguna otra clase. Las buenas opciones son su propia implementación de laApplication
o unaService
(también hay algunas variaciones de esta solución si desea verificar la visibilidad de la actividad desde el servicio).Ejemplo
Implementar
Application
clase personalizada (tenga en cuenta elisActivityVisible()
método estático):Registre su clase de aplicación en
AndroidManifest.xml
:Agregue
onPause
yonResume
a cada unoActivity
en el proyecto (puede crear un antepasado común para sus Actividades si lo desea, pero si su actividad ya se ha extendido desdeMapActivity
/ListActivity
etc. aún debe escribir lo siguiente a mano):Update
ActivityLifecycleCallbacks se agregaron en el nivel 14 de API (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 obtener más detalles.
El incorrecto
solía sugerir la siguiente solución:
Si bien esta solución puede funcionar (y de hecho funciona la mayor parte del tiempo), recomiendo abstenerse de usarla. Y he aquí por qué. Como escribió Dianne Hackborn :
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.
Otra solución incorrecta que la biblioteca
Droid-Fu mencionó en una de las respuestas utiliza
ActivityManager.getRunningTasks
para suisApplicationBroughtToBackground
método. Vea el comentario de Dianne arriba y tampoco use ese método.fuente
OnStop
solicitud deisActivityVisible
.NO USE ESTA RESPUESTA
La respuesta del usuario1269737 es la forma correcta (aprobada por Google / Android) de hacer esto . Ve a leer su respuesta y dales un +1.
Dejaré mi respuesta original aquí por el bien de la posteridad. Este fue el mejor disponible en 2012, pero ahora Android tiene el soporte adecuado para esto.
Respuesta original
La clave está usando
ActivityLifecycleCallbacks
(tenga en cuenta que esto requiere el nivel 14 de la API 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, su aplicación está en segundo plano. Si hay más actividades iniciadas, su aplicación aún está 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, entonces: visible y en primer plano, visible pero no en primer plano, y no visible y no en primer plano (es decir, en segundo plano).Lo realmente bueno de este método es que no tiene los problemas asincrónicos
getRunningTasks()
, pero tampoco tiene que modificar cada unoActivity
en su aplicación para configurar / desarmar algo enonResumed()
/onPaused()
. Son solo unas pocas líneas de código que son independientes y funcionan en toda la aplicación. Además, tampoco se requieren permisos originales.MyLifecycleHandler.java:
MyApplication.java:
@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; ¿Es eso un problema aquí?No. Los documentos para
onStop()
decir:La clave aquí es "mantener el proceso de su actividad ejecutándose ..." Si alguna vez se llega a esta situación de poca memoria, su proceso se anula (no solo su actividad). Esto significa que este método de verificación de fondo sigue siendo válido porque a) no puede verificar el fondo de todos modos si su proceso se anula, yb) si su proceso comienza nuevamente (porque se crea una nueva actividad), el miembro las variables (ya sea estáticas o no) para
MyLifecycleHandler
se restablecerán a0
.¿Funciona esto para cambios de configuración?
Por defecto, no. Debe 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 su actividad será destruida y recreada. Si no se establece esto, los métodos de su actividad serán llamados en el orden siguiente: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 cómo funciona este método de detección de fondo). Para evitar esto, debe configurarloconfigChanges
para que su actividad no se destruya. Afortunadamente, tuve que configurarconfigChanges
Ya en todos mis proyectos porque no era deseable que toda mi actividad se destruyera en la pantalla, gire / cambie el tamaño, por lo que nunca he encontrado 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 estar en primer plano (por ejemplo, si hay una superposición de notificaciones transparente). Es por eso que actualicé esta respuesta para reflejar eso.
Es importante saber que Android tiene un momento de limbo extraño al cambiar actividades donde nada está en primer plano . Por esta razón, si verifica si su aplicación está en primer plano al cambiar entre actividades (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 comprobar si su aplicación está en primer plano en su
Activity
'sonPause()
método despuéssuper.onPause()
. Solo recuerda el extraño estado del limbo del que acabo de hablar.Puede comprobar si su aplicación es visible (es decir, si no es en el fondo) en su
Activity
'sonStop()
método despuéssuper.onStop()
.fuente
onStop()
despuéssuper.onStop()
. No verifique el fondo enonPause()
.SOLUCIÓN DE GOOGLE : no es un truco, como las soluciones anteriores. Utilice ProcessLifecycleOwner
Kotlin:
Java:
en app.gradle
Puede leer más sobre los componentes de arquitectura relacionados con el ciclo de vida aquí: https://developer.android.com/topic/libraries/architecture/lifecycle
fuente
companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }
entonces puedes obtener el estado de primer plano conArchLifecycleApp.isForeground()
The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes.
, esto no funciona para lasmultiple processes
aplicaciones, ¿hay alguna API que podamos lograr con elegancia?A partir de la versión 26 de la biblioteca de soporte, puede usar ProcessLifecycleOwner , simplemente agréguelo a su dependencia como se describe aquí , por ejemplo:
Y luego solo consulta
ProcessLifecycleOwner
cuando quieras el estado de la aplicación, ejemplos:fuente
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 como para usarlo cuando su servicio recibe actualizaciones del servidor y tiene que decidir si mostrar notificación o no (porque si la IU está en primer plano, el usuario notará la actualización sin notificación).
fuente
JobService
para detectar que el servicio se está ejecutando en segundo plano.La respuesta de Idolon es propensa a errores y es mucho más complicada, aunque en este caso, verifique que la aplicación de Android esté en primer plano o no. y aquí Determinar la aplicación actual en primer plano a partir de una tarea o servicio en segundo plano
Hay un enfoque mucho más simple:
En una BaseActivity que todas las actividades se extienden:
Siempre que necesite verificar si alguna de las actividades de su aplicación está en primer plano, simplemente verifique
isVisible()
;Para comprender este enfoque, consulte esta respuesta del ciclo de vida de la actividad en paralelo : Ciclo de vida de la actividad en paralelo
fuente
Idolon's answer is error prone
- desafortunadamente tengo que estar de acuerdo contigo. Según el comentario de Dianne Hackborn en los Grupos de Google, actualicé mi respuesta. Compruébalo por favor para los detalles.onPause
,onStop
ni elonResume
evento se llama. Entonces, ¿qué haces si ninguno de estos eventos se dispara?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 fácil y directa que describo a continuación.
Esa es también la principal diferencia entre
onStop()
yonPause()
que ninguno mencionó en los artículos que leí.Entonces, según el comportamiento del ciclo de vida de esta actividad, simplemente puede contar cuántas veces lo hizo
onStart()
yonPause()
recibió llamadas en su programa. Tenga en cuenta que para cada unoActivity
de sus programas, debe anularonStart()
yonStop()
, para aumentar / disminuir la variable estática utilizada para contar. A continuación se muestra el código que implementa esta lógica. Tenga en cuenta que estoy usando una clase que se extiendeApplication
, así que no se olvide de declarar en laManifest.xml
etiqueta de la aplicación:android:name=".Utilities"
aunque también se puede implementar usando una clase personalizada simple.Ahora en cada actividad de nuestro programa, debemos anular
onStart()
yonStop()
e incremento / decremento como se muestra a continuación:Con esta lógica, hay 2 casos posibles:
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.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 cual es imposible. Si encuentra este caso, significa que no está aumentando / disminuyendo el contador como debería.Estás listo para partir Debería verificar si su aplicación está en segundo plano en el interior
onStop()
.fuente
if(Utilities.isApplicationOnBackground()) …
aUtilities
. Porque de lo contrario, solo una actividad específica reaccionará al evento.No hay forma, salvo que lo rastree usted mismo, para determinar si alguna de sus actividades es visible o no. Quizás debería considerar hacer una nueva pregunta de StackOverflow, explicando qué es lo que está tratando de lograr a partir de una experiencia de usuario, para que quizás podamos darle ideas de implementación alternativas.
fuente
Service
. Si es así, haga que sus actividades notifiquen al servicio a medida que aparecen y desaparecen. SiService
determina que no hay actividades visibles y permanece así durante cierto tiempo, detenga la transferencia de datos en el siguiente punto de detención lógico. Sí, esto requerirá un código para cada una de sus actividades, pero en este momento, eso es inevitable AFAIK.MyActivityClass
heredeActivity
e implemente los métodos del ciclo de vida, y haga que todas sus actividades hereden deMyActivityClass
. Esto no hay trabajo paraPreferenceActivity
oMapActivity
embargo (véase esta pregunta )Puede usar ComponentCallbacks2 para detectar si la aplicación está en segundo plano. Por cierto, esta devolución de llamada solo está disponible en API Nivel 14 (Ice Cream Sandwich) y superiores.
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 un
activity
,service
, etc.fuente
A partir de la respuesta @Cornstalks se incluyen un par de funciones útiles.
Características adicionales:
App.java
AppLifecycleHandler.java
fuente
La mejor solución que se me ocurrió utiliza temporizadores.
Ha iniciado un temporizador en onPause () y cancela el mismo temporizador en onResume (), hay 1 instancia del temporizador (generalmente definido en la clase Aplicación). El temporizador en sí está configurado para ejecutar un Runnable después de 2 segundos (o cualquier intervalo que considere apropiado), cuando se activa el temporizador, establece una bandera 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 posterior y no requiere ningún permiso para implementar.
Esta solución funciona bien si también usa un bus de eventos, ya que su temporizador simplemente puede disparar un evento y varias partes de su aplicación pueden responder en consecuencia.
fuente
Si activa la configuración del desarrollador "No mantener actividades", compruebe que solo el recuento de actividades creadas no es suficiente. Debe verificar también isSaveInstanceState . Mi método personalizado esAplicaciónRunning () es ejecutar la aplicación de Android:
Aquí mi código de trabajo:
fuente
La única solución correcta:
MainActivity.java:
MyApp.java:
fuente
Para aprovechar lo que han dicho CommonsWare y Key, quizás podría extender la clase de aplicación y hacer que todas sus actividades llamen a eso en sus métodos onPause / onResume. Esto le permitiría saber qué Actividad (es) están visibles, pero esto probablemente podría manejarse mejor.
¿Puedes explicar exactamente lo que tienes en mente? Cuando dice que se ejecuta en segundo plano, ¿quiere decir simplemente que su aplicación aún está en la memoria aunque no esté actualmente en la pantalla? ¿Ha considerado usar los Servicios como una forma más persistente de administrar su aplicación cuando no está enfocada?
fuente
Application
no tieneonPause()
oonResume()
.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:
En segundo lugar, implementé esta interfaz en la clase de mi aplicación:
Tercero, estoy creando una clase que se extiende desde SherlockActivity:
Cuarto, todas las clases que se extienden desde SherlockActivity, reemplacé por MySherlockActivity:
Ahora, en el logcat verá los registros programados en la implementación de la interfaz realizada en MyApplication.
fuente
La actividad se detiene cuando aparece un cuadro de diálogo, por lo que todas las soluciones recomendadas son medias soluciones. También necesita crear ganchos para los diálogos.
fuente
Como ya no se menciona, sugeriré a los lectores que exploren ProcessLifecycleOwner disponible a través de los componentes de Android Architecture
fuente
Documentos oficiales:
El sistema distingue entre aplicaciones en primer plano y en segundo plano. (La definición de fondo para fines de limitaciones de 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 en lo que respecta a su capacidad para iniciar servicios). se considera que está en primer plano si se cumple alguna de las siguientes condiciones:
Si ninguna de esas condiciones es verdadera, se considera que la aplicación está en segundo plano.
fuente
Otra solución para esta publicación anterior (para aquellos que podría ayudar):
fuente
Vea el comentario en la función onActivityDestroyed.
Funciona con SDK target versión 14>:
fuente
Debe usar una preferencia compartida para almacenar la propiedad y actuar sobre ella utilizando el enlace de servicio de sus actividades. Si usa solo el enlace, (eso nunca es usar startService), entonces su servicio se ejecutará solo cuando lo enlace, (bind onResume y unbind onPause) que haría que se ejecute solo en primer plano, y si desea trabajar en En segundo plano, puede utilizar el servicio regular de inicio y parada.
fuente
Creo que esta pregunta debería ser más clara. ¿Cuando? ¿Dónde? ¿Cuál es su situación específica que desea conocer si su aplicación está en segundo plano?
Acabo de presentar mi solución en mi camino.
Lo hago al usar el campo "importancia" de la
RunningAppProcessInfo
clase en elonStop
método de cada actividad en mi aplicación, lo que se puede lograr simplemente proporcionando unaBaseActivity
extensión para otras actividades que implementa elonStop
método para verificar el valor de "importancia". Aquí está el código:fuente
Recomiendo leer esta página: http://developer.android.com/reference/android/app/Activity.html
En resumen, su actividad ya no es visible después de
onStop()
haber sido llamada.fuente
onStop
; entreonPause
yonStop
es visible , pero no en primer plano .onStop()
se llama, que está alineada con lo que escribió.onPause
se llama: una edición reciente te ha corregido.¿Qué pasa con el uso de getApplicationState (). IsInForeground ()?
fuente
En mi opinión, muchas respuestas introducen una gran carga de código y traen mucha complejidad y no legibilidad.
Cuando la gente pregunta sobre SO cómo comunicar entre una
Service
y unaActivity
, por lo general consejos para utilizar la LocalBroadcastManager .¿Por qué?
Bueno, citando los documentos:
No en los documentos:
Activity
,Application
, ...Descripción
Por lo tanto, desea verificar si alguno de ellos
Activity
está actualmente en primer plano. Usualmente haces eso en unService
, o tuApplication
clase.Esto significa que sus
Activity
objetos se convierten en el emisor de una señal (estoy encendido / apagado). TuService
, por otro lado, se convierte en elReceiver
.Hay dos momentos en que su
Activity
te dice si está en primer plano o en segundo plano (sí, solo dos ... no 6).Cuando
Activity
entra en primer plano,onResume()
se activa el método (también llamado despuésonCreate()
).Cuando
Activity
va en la parte de atrás,onPause()
se llama.Estos son los momentos en los que
Activity
debe enviar la señal a suService
para describir su estado.En caso de múltiples
Activity
, recuerde elActivity
pasa al fondo primero, luego otro entra en primer plano.Entonces la situación sería: *
El
Service
/Application
simplemente seguirá escuchando esas señales y actuará en consecuencia.Código (TLDR)
Su
Service
debe implementar unBroadcastReceiver
fin de escuchar señales.Registra el
Receiver
enService::onCreate()
Anular el registro en
Service::onDestroy()
Ahora tu
Activity
debe comunicar su estado.En
Activity::onResume()
En
Activity::onPause()
Una situación muy, muy común.
Por lo general, no es necesario verificar si
Activity
está en primer plano o no. Simplemente envíe los datos a travésLocalBroadcastManager
de suService
. SiActivity
está activado, responderá y actuará.Para esta situación muy común, el se
Service
convierte en el remitente y elActivity
implementa elBroadcastReceiver
.Entonces, crea un
Receiver
en tuActivity
. RegístreseonResume()
y anule el registroonPause()
. No es necesario utilizar los otros métodos de ciclo de vida. .Defina el
Receiver
comportamiento enonReceive()
(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 queActivity
esté encendido responderá (si también implementanReceiver
).Si todos están en segundo plano, nadie responderá y la señal simplemente se perderá.
Envíe los datos desde la
Service
víaIntent
(consulte el código anterior) especificando la ID de la señal.fuente
fuente
Ninguna de las respuestas se ajusta al caso específico si se busca saber si una actividad específica está en primer plano y si usted es un SDK sin acceso directo a la Aplicación. Para mí, estaba en el hilo de fondo después de recibir una notificación automática para un nuevo mensaje de chat y solo quería mostrar una notificación del sistema si la pantalla de chat no estaba en primer plano.
Usando
ActivityLifecycleCallbacks
eso como se ha recomendado en otras respuestas, he creado una pequeña clase de utilidad que alberga la lógica de siMyActivity
está en primer plano o no.}
fuente
En mis actividades onResume y onPause escribo un booleano isVisible en SharedPrefences.
Y léalo en otro lugar cuando sea necesario a través de,
Tal vez no sea elegante, pero funciona para mí ...
fuente
Puede ser demasiado tarde para responder, pero si alguien viene de visita, entonces esta es la solución que sugiero. Para mostrar tostadas y notificaciones cuando el usuario está en BG. 2. Para realizar algunas tareas por primera vez, el usuario proviene de BG, como una encuesta, redibujar, etc.
La solución de Idolon y otros se encarga de la primera parte, pero no para la segunda. Si hay varias actividades en su aplicación, y el usuario está cambiando entre ellas, entonces cuando esté en la segunda actividad, la bandera visible será falsa. Por lo tanto, no se puede usar de manera determinista.
Hice algo que fue sugerido por CommonsWare, "Si el Servicio determina que no hay actividades visibles, y permanece así por un período de tiempo , detenga la transferencia de datos en el siguiente punto lógico de detención".
La línea en negrita es importante y se puede usar para lograr el segundo elemento. Entonces, lo que hago es que una vez que obtengo el onActivityPaused (), no cambie el visible a falso directamente, en su lugar tenga un temporizador de 3 segundos (ese es el máximo para que se inicie la próxima actividad), y si no hay onActivityResumed ( ) llame en los próximos 3 segundos, cambie visible a falso. Del mismo modo en onActivityResumed () si hay un temporizador, lo cancelo. En resumen, lo visible se convierte en isAppInBackground.
Lo sentimos, no puedo copiar y pegar el código ...
fuente
Me gustaría recomendarle que use 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 back-end, no lo muestre.
Su aplicación puede escribir continuamente la hora actual en un archivo específico. Mientras su aplicación se está iniciando, verifique la última marca de tiempo, si current_time-last_time> el rango de tiempo que especificó para escribir la última hora, significa que su aplicación se detiene, ya sea eliminada por el sistema o el propio usuario.
fuente