¿Cómo comprobar si la actividad está en primer plano o en un fondo visible?

Resuelto Nick asked hace 54 años • 25 respuestas

Tengo una pantalla de presentación en un temporizador. Mi problema es que antes de realizar finish()mi actividad necesito verificar que la siguiente actividad haya comenzado porque aparece un cuadro de diálogo del sistema y solo quiero finish(); una vez que el usuario ha seleccionado una opción en el cuadro de diálogo?

Sé que hay muchas preguntas sobre cómo ver si tu actividad está en primer plano, pero no sé si esto también permite cuadros de diálogo encima de la actividad.

Aquí está el problema, el rojo es mi actividad que está en segundo plano mientras que el diálogo está en primer plano:

el rojo es mi actividad que está en segundo plano mientras que el diálogo está en primer plano

EDITAR: Intenté simplemente no usarlo finish(), pero luego puedo volver a mi actividad en la pila de aplicaciones que estoy tratando de evitar.

Nick avatar Jan 01 '70 08:01 Nick
Aceptado

Esto es lo que se recomienda como solución correcta :

La solución adecuada (los créditos son para Dan, CommonsWare y NeTeInStEiN) Realice un seguimiento de la visibilidad de su aplicación usted mismo utilizando los métodos Activity.onPause y Activity.onResume. Almacene el estado de "visibilidad" en alguna otra clase. Una buena opción es su propia implementación de la Aplicación o un Servicio (también existen algunas variaciones de esta solución si desea verificar la visibilidad de la actividad desde el servicio).

Ejemplo Implementar una clase de aplicación 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 actividad en el proyecto (puede crear un ancestro común para sus actividades si lo desea, pero si su actividad ya está extendida desde MapActivity/ListActivity, 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();
}

En su finish()método, desea utilizarlo isActivityVisible()para verificar si la actividad es visible o no. Allí también podrás comprobar si el usuario ha seleccionado una opción o no. Continúe cuando se cumplan ambas condiciones.

La fuente también menciona dos soluciones incorrectas... así que evita hacerlo.

Fuente: desbordamiento de pila

Si apunta al nivel API 14 o superior, se puede usar android.app.Application.ActivityLifecycleCallbacks.

public class MyApplication extends Application implements ActivityLifecycleCallbacks {
    private static boolean isInterestingActivityVisible;

    @Override
    public void onCreate() {
        super.onCreate();
    
        // Register to be notified of activity state changes
        registerActivityLifecycleCallbacks(this);
        // ...
    }

    public boolean isInterestingActivityVisible() {
        return isInterestingActivityVisible;
    }

    @Override
    public void onActivityResumed(Activity activity) {
        if (activity instanceof MyInterestingActivity) {
             isInterestingActivityVisible = true;
        }
    }

    @Override
    public void onActivityStopped(Activity activity) {
        if (activity instanceof MyInterestingActivity) {
             isInterestingActivityVisible = false;
        }
    }

    // Other state change callback stubs
    // ...
}
Himanshu Likhyani avatar Jul 24 '2014 13:07 Himanshu Likhyani

UPD : actualizado al estado Lifecycle.State.RESUMED. Gracias a @htafoya por eso.

En 2019, con la ayuda de la nueva biblioteca de soporte 28+o AndroidX, simplemente puedes usar:

val isActivityInForeground = activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)

Puede leer más en la documentación para comprender lo que sucedió bajo el capó.

Alex Misiulia avatar Feb 08 '2019 09:02 Alex Misiulia

Activity::hasWindowFocus() te devuelve el valor booleano que necesitas.

public class ActivityForegroundChecker extends TimerTask
{
    private static final long FOREGROUND_CHECK_PERIOD = 5000;
    private static final long FIRST_DELAY             = 3000;

    private Activity m_activity;
    private Timer    m_timer;

    public ActivityForegroundChecker (Activity p_activity)
    {
        m_activity = p_activity;
    }

    @Override
    public void run()
    {
        if (m_activity.hasWindowFocus() == true) {
            // Activity is on foreground
            return;
        }
        // Activity is on background.
    }

    public void start ()
    {
        if (m_timer != null) {
            return;
        }
        m_timer = new Timer();
        m_timer.schedule(this, FIRST_DELAY, FOREGROUND_CHECK_PERIOD);
    }

    public void stop ()
    {
        if (m_timer == null) {
            return;
        }
        m_timer.cancel();
        m_timer.purge();
        m_timer = null;
    }
}

Aquí tienes una clase de ejemplo para comprobar la visibilidad de tus actividades desde donde estés.

Recuerda que si muestras un diálogo , el resultado será falso ya que el diálogo tendrá el foco principal. Aparte de eso, es realmente útil y más confiable que las soluciones sugeridas.

Burak Day avatar Jan 05 '2018 11:01 Burak Day