Android: ¿cómo verifico si la actividad se está ejecutando?

152

¿Hay alguna forma simple de determinar si una determinada actividad está activa o no? Quiero hacer ciertas cosas dependiendo de qué actividad esté activa. p.ej:

if(activityrunning == activity1)
//do this
else if (activityrunning == activity2)
//do something else
usuario560571
fuente
Para verificar si una Actividad se está ejecutando o no, puede consultar esta respuesta: stackoverflow.com/a/39079627/4531507
Rahul Sharma

Respuestas:

227

Puedes usar una staticvariable dentro de la actividad.

class MyActivity extends Activity {
     static boolean active = false;

      @Override
      public void onStart() {
         super.onStart();
         active = true;
      } 

      @Override
      public void onStop() {
         super.onStop();
         active = false;
      }
}

El único inconveniente es que si lo usa en dos actividades que se vinculan entre sí, onStopla primera a veces se llama después onStarten la segunda. Entonces, ambas podrían ser ciertas brevemente.

Dependiendo de lo que intente hacer (¿actualizar la actividad actual de un servicio?). Simplemente puede registrar un escucha estático en el servicio en su onStartmétodo de actividad y luego el escucha correcto estará disponible cuando su servicio quiera actualizar la IU.

siliconaagle
fuente
55
Alguien me señaló esto ... La preferencia compartida debería preferirse a una variable estática debido a problemas de pérdida de memoria.
Ayush Goyal
13
¿Qué pasa si hay diferentes actividades de la misma clase ejecutándose? Lo que si se amplía MyActivitycon MyChildactivityy desea comprobar si el niño está activo?
Señor Smith
2
Dependiendo de su definición de "ejecución", es posible que desee cambiar el estado de la variable en onResume y onPause ....
G. Blake Meike
55
Esta solución no es una buena solución en absoluto. Digamos que su Actividad llama a un Fragmento, por ejemplo, el fragmento estará sobre la Actividad pero la Actividad no llamará a onPause, y si cierra el fragmento onStop, onStart o cualquier otro método del ciclo de vida tampoco se llamará. La mejor solución es verificar en su clase de Aplicación la visibilidad como se describe aquí: stackoverflow.com/questions/18038399/…
portfoliobuilder
66
Si recomiendas estadísticas, obtienes un -1 de mí
Matei Suica
52

Me doy cuenta de que este problema es bastante antiguo, pero creo que aún vale la pena compartir mi solución, ya que podría ser útil para otros.

Esta solución no estaba disponible antes de que se lanzaran los Componentes de Arquitectura de Android.

La actividad es al menos parcialmente visible

getLifecycle().getCurrentState().isAtLeast(STARTED)

La actividad está en primer plano

getLifecycle().getCurrentState().isAtLeast(RESUMED)
Malinjir
fuente
3
getLifecycle (). getCurrentState (). isAtLeast (Lifecycle.State.RESUMED)
Radhey
43

Creo que más claro así:

  public boolean isRunning(Context ctx) {
        ActivityManager activityManager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);

        for (RunningTaskInfo task : tasks) {
            if (ctx.getPackageName().equalsIgnoreCase(task.baseActivity.getPackageName())) 
                return true;                                  
        }

        return false;
    }
Xenione
fuente
2
Intento evitar hacer variables temporales antes de un ciclo 'for'; for (RunningTaskInfo task: ActivityManager.getRunningTasks (Integer.MAX_VALUE)) {...
mikebabcock
¿Cómo puedo llamar a esta función?
Behzad
1
como de costumbre, es un método que puede llamar dentro de su clase como una 'función' ¿necesita un ejemplo?
Xenione
10
De developer.android.com/reference/android/app/… "Esto nunca debe usarse para la lógica central en una aplicación, como decidir entre diferentes comportamientos en función de la información que se encuentra aquí. Dichos usos no son compatibles y probablemente se romperán en el futuro."
joe_deniable
15
A partir del nivel 21 de API (Android 5.0 Lollipop), este método ha quedado en desuso.
AxeEffect
30

Una opción sin usar ninguna variable auxiliar es:

activity.getWindow().getDecorView().getRootView().isShown()

donde la actividad es fe: this o getActivity ().

El valor devuelto por esta expresión cambia en onStart () / onStop (), que son los eventos que comienzan / detienen mostrando el diseño de la actividad en el teléfono.

GaRRaPeTa
fuente
16
¿Por qué no usarlo Activity#getWindow().getDecorView().isShown()?
Gianluca P.
24

Usé el método MyActivity.class y getCanonicalName y obtuve una respuesta.

protected Boolean isActivityRunning(Class activityClass)
{
        ActivityManager activityManager = (ActivityManager) getBaseContext().getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);

        for (ActivityManager.RunningTaskInfo task : tasks) {
            if (activityClass.getCanonicalName().equalsIgnoreCase(task.baseActivity.getClassName()))
                return true;
        }

        return false;
}
mahyar
fuente
1
Como se mencionó anteriormente, puede que no sea una buena idea usarlo, getRunningTasks()ya que fue obsoleto: androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/…
Vitalii Dmitriev
21

Mucho mejor manera que usar una variable estática y seguir OOP

Shared Preferencesse puede usar para compartir variables con otros activitiesy servicios de unoapplication

    public class example extends Activity {

    @Override
    protected void onStart() {
        super.onStart();

        // Store our shared preference
        SharedPreferences sp = getSharedPreferences("OURINFO", MODE_PRIVATE);
        Editor ed = sp.edit();
        ed.putBoolean("active", true);
        ed.commit();
    }

    @Override
    protected void onStop() {
        super.onStop();

        // Store our shared preference
        SharedPreferences sp = getSharedPreferences("OURINFO", MODE_PRIVATE);
        Editor ed = sp.edit();
        ed.putBoolean("active", false);
        ed.commit();

    }
}

Usa las preferencias compartidas. Tiene la información de estado más confiable, menos problemas de cambio / destrucción de aplicaciones, nos ahorra pedir otro permiso y nos da más control para decidir cuándo nuestra actividad es realmente la más importante. ver detalles aquí abd aquí también

Zar E Ahmer
fuente
Gracias. ¿Pero onResume también se necesita hermano?
1
Depende de lo que entiendas por activo. Según mi código, la actividad está en la pila y luego está activa. Y si desea manejar visible o no, puede usar onResume
Zar E Ahmer el
19
Esto se rompe cuando se mata la actividad sin llamaronStop()
Marcel Bro
3
¿Qué sucede si la aplicación falla?
ucMedia
1
Esta es una "solución" muy peligrosa.
Firzen
9

Este es un código para verificar si se está ejecutando un servicio en particular. Estoy bastante seguro de que también puede funcionar para una actividad siempre que cambie getRunningServices con getRunningAppProcesses () o getRunningTasks (). Echa un vistazo aquí http://developer.android.com/reference/android/app/ActivityManager.html#getRunningAppProcesses ()

Cambie Constants.PACKAGE y Constants.BACKGROUND_SERVICE_CLASS en consecuencia

    public static boolean isServiceRunning(Context context) {

    Log.i(TAG, "Checking if service is running");

    ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);

    List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

    boolean isServiceFound = false;

    for (int i = 0; i < services.size(); i++) {

        if (Constants.PACKAGE.equals(services.get(i).service.getPackageName())){

            if (Constants.BACKGROUND_SERVICE_CLASS.equals(services.get(i).service.getClassName())){
                isServiceFound = true;
            }
        }
    }

    Log.i(TAG, "Service was" + (isServiceFound ? "" : " not") + " running");

    return isServiceFound;

}
kkudi
fuente
1
Pero tenga en cuenta que el enlace que proporciona indica que "este método solo está destinado a depurar o crear una IU de gestión de procesos orientada al usuario".
joe_deniable
getRunningTasks ahora está en desuso.
Adi
5

Hay una manera mucho más fácil que todo lo anterior y este enfoque no requiere el uso android.permission.GET_TASKSen el manifiesto, o tiene el problema de las condiciones de carrera o las pérdidas de memoria señaladas en la respuesta aceptada.

  1. Hacer una variable ESTÁTICA en la Actividad principal. Static permite que otras actividades reciban los datos de otra actividad. onPause()establecer esta variable falsa , onResumey onCreate()establecer esta variable verdadera .

    private static boolean mainActivityIsOpen;
  2. Asigna getters y setters de esta variable.

    public static boolean mainActivityIsOpen() {
        return mainActivityIsOpen;
    }
    
    public static void mainActivityIsOpen(boolean mainActivityIsOpen) {
        DayView.mainActivityIsOpen = mainActivityIsOpen;
    }
    
  3. Y luego de otra actividad o servicio

    if (MainActivity.mainActivityIsOpen() == false)
    {
                    //do something
    }
    else if(MainActivity.mainActivityIsOpen() == true)
    {//or just else. . . ( or else if, does't matter)
            //do something
    }
    
coolcool1994
fuente
3
¿Estás diciendo que usar métodos de acceso es mejor que usar variables públicas estáticas sin procesar?
IgorGanapolsky
1
En Java es mejor usar setters y getters para mantener sus variables privadas. Sin embargo, creo que en Android es común acceder a las variables públicas directamente ...
Stephen
11
No tiene sentido tener un setter público ya que el estado de la actividad debe ser manejado solo por la actividad misma. Debe seguir con las convenciones de nomenclatura de Java: isActivityOpen sería un método getter correcto. También usar if boolean == true es redundante. Además de eso, delegar la gestión del estado a la actividad es el mejor enfoque.
Lisandro
8
esta es la razón por la que debería haber asistido a sus cursos más diligentemente @coolcool;)
Jerec TheSith
1
¿Y si tiene varias instancias de la actividad en ejecución?
nickmartens1980
5
if(!activity.isFinishing() && !activity.isDestroyed())

De los documentos oficiales:

Activity # isFinishing ()

Verifique si esta actividad está en proceso de finalización, ya sea porque llamó a finish () o porque alguien más ha solicitado que finalice. Esto se usa a menudo en onPause () para determinar si la actividad es simplemente pausar o terminar por completo.

Activity # isDestroyed ()

Devuelve verdadero si la última llamada onDestroy () se ha realizado en la Actividad, por lo que esta instancia ahora está muerta.

Codelicious
fuente
4

gracias kkudi! Pude adaptar tu respuesta al trabajo para una actividad ... esto es lo que funcionó en mi aplicación ...

public boolean isServiceRunning() { 

ActivityManager activityManager = (ActivityManager)Monitor.this.getSystemService (Context.ACTIVITY_SERVICE); 
    List<RunningTaskInfo> services = activityManager.getRunningTasks(Integer.MAX_VALUE); 
    isServiceFound = false; 
    for (int i = 0; i < services.size(); i++) { 
        if (services.get(i).topActivity.toString().equalsIgnoreCase("ComponentInfo{com.lyo.AutoMessage/com.lyo.AutoMessage.TextLogList}")) {
            isServiceFound = true;
        }
    } 
    return isServiceFound; 
} 

este ejemplo le dará un verdadero o falso si topActivity coincide con lo que está haciendo el usuario. Entonces, si la actividad que está buscando no se muestra (es decir, está en Pausa), no obtendrá una coincidencia. Además, para hacer esto, debe agregar el permiso a su manifiesto.

<uses-permission  android:name="android.permission.GET_TASKS"/>

¡Espero que esto haya sido útil!

alyon2002
fuente
1
Este permiso de uso quedó en desuso en el nivel 21 de la API. Developer.android.com/reference/android/…
Guy West
2
Vota en contra de la respuesta para acceder a la actividad principal (servicios [i] .topActivity) minamos el nivel de API Q. Por debajo de eso no funcionará.
Debasish Ghosh
4

Creo que la respuesta aceptada es una forma horrible de manejar esto.

No sé cuál es el caso de uso, pero considere un método protegido en la clase base

@protected
void doSomething() {
}

y anularlo en la clase derivada.

Cuando se produce el evento, simplemente llame a este método en la clase base. La clase 'activa' correcta lo manejará entonces. La clase misma puede verificar si no es así Paused().

Mejor aún, use un bus de eventos como GreenRobot's , Square's , pero ese está en desuso y sugiere usar RxJava

Chico
fuente
2

Usé un cheque if (!a.isFinishing())y parece hacer lo que necesito. aes la instancia de actividad. ¿Es esto incorrecto? ¿Por qué nadie intentó esto?

lxknvlk
fuente
2

qué pasa activity.isFinishing()

Ambareesh B
fuente
No es una buena solución porque el acabado indica si hay actividad en un proceso de muerte.
VelocityPulse
2

ActivityLifecycleCallbacks es una excelente manera de realizar un seguimiento de todas las actividades en la aplicación:

public class BaseActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {

private ActivityState homeState, contentState;

@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.CREATED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.CREATED;
    }
}

@Override
public void onActivityStarted(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.STARTED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.STARTED;
    }
}

@Override
public void onActivityResumed(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.RESUMED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.RESUMED;
    }
}

@Override
public void onActivityPaused(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.PAUSED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.PAUSED;
    }
}

@Override
public void onActivityStopped(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.STOPPED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.STOPPED;
    }
}

@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}

@Override
public void onActivityDestroyed(Activity activity) {
    if (activity instanceof HomeActivityv2) {
        homeState = ActivityState.DESTROYED;
    } else if (activity instanceof ContentDisplayActivity) {
        contentState = ActivityState.DESTROYED;
    }
}

public ActivityState getHomeState() {
    return homeState;
}

public ActivityState getContentState() {
    return contentState;
}
}

ActivityState:

public enum ActivityState {
    CREATED, STARTED, RESUMED, PAUSED, STOPPED, DESTROYED;
}

Extienda la clase de aplicación y proporcione su referencia en el archivo de manifiesto de Android:

import android.app.Application;

public final class BaseApplication extends Application {
private BaseActivityLifecycleCallbacks baseALC;

@Override
public void onCreate() {
    super.onCreate();
    baseALC = new BaseActivityLifecycleCallbacks();
    this.registerActivityLifecycleCallbacks(baseALC);

}

public BaseActivityLifecycleCallbacks getBaseALC() {
    return baseALC;
}
}

Haga clic en cualquier lugar de Actividad para ver el estado de otra actividad:

private void checkAndLaunchHomeScreen() {
    Application application = getApplication();
    if (application instanceof BaseApplication) {
        BaseApplication baseApplication = (BaseApplication) application;
        if (baseApplication.getBaseALC().getHomeState() == null || baseApplication.getBaseALC().getHomeState() == ActivityState.DESTROYED) {
            //Do anything you want
        }
    }
}

https://developer.android.com/reference/android/app/Application.ActivityLifecycleCallbacks.html

Suyash Gupta
fuente
1

No estoy seguro de que sea una forma "adecuada" de "hacer cosas".
Si no hay una forma API para resolver la (o una) pregunta de lo que debería pensar un poco, tal vez esté haciendo algo mal y lea más documentos, etc.
(Como entendí, las variables estáticas son una forma comúnmente incorrecta en Android. Por causa podría funcionar, pero definitivamente habrá casos en los que no funcionará [por ejemplo, en producción, en millones de dispositivos]).
Exactamente en su caso, le sugiero que piense por qué necesita saber si otra actividad está viva ... puede comenzar otra actividad para obtener resultados para obtener su funcionalidad. O puede derivar la clase para obtener su funcionalidad, etc.
Atentamente.

usuario2399321
fuente
1

Si está interesado en el estado del ciclo de vida de la instancia específica de la actividad, la solución de siliconagle se ve correcta, excepto que la nueva variable "activa" debería ser una variable de instancia, en lugar de estática.

Jonathan Taylor
fuente
1

Use una transmisión ordenada. Ver http://android-developers.blogspot.nl/2011/01/processing-ordered-broadcasts.html

En su actividad, registre un receptor en onStart, anule el registro en onStop. Ahora, por ejemplo, cuando un servicio necesita manejar algo que la actividad podría hacer mejor, envíe una transmisión ordenada desde el servicio (con un controlador predeterminado en el propio servicio). Ahora puede responder en la actividad cuando se está ejecutando. El servicio puede verificar los datos de resultados para ver si se manejó la transmisión y, si no, tomar las medidas apropiadas.

nickmartens1980
fuente
1

Además de la respuesta aceptada , si tiene varias instancias de la actividad, puede usar un contador en su lugar:

class MyActivity extends Activity {

     static int activeInstances = 0;

     static boolean isActive() {
        return (activeInstance > 0)
     }

      @Override
      public void onStart() {
         super.onStart();
         activeInstances++;
      } 

      @Override
      public void onStop() {
         super.onStop();
         activeInstances--;
      }
}
james_alvarez
fuente
faltan "s" y "; (punto y coma)" en la línea de retorno.
Ali_dev
1

Has probado..

    if (getActivity() instanceof NameOfYourActivity){
        //Do something
    }
E.Mathew
fuente
0

Encontramos una solución fácil con el siguiente código

@Override 
protected void onCreate(Bundle savedInstanceState) { 
            super.onCreate(savedInstanceState); 
            if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) { 
                // Activity is being brought to front and not being  created again, 
                // Thus finishing this activity will bring the last viewed activity to foreground
                finish(); 
            } 
    }
Varun Bhatia
fuente
0

Use la variable isActivity para verificar si la actividad está viva o no.

private boolean activityState = true;

 @Override
protected void onDestroy() {
    super.onDestroy();
    activityState = false;
}

Entonces revisa

if(activityState){
//add your code
}
Faran Tariq
fuente
0

Si desea verificar si la actividad está en la pila posterior, simplemente siga los siguientes pasos. 1. Declarado una ArrayList en su clase de Aplicación [La clase de aplicación se define en su archivo mainfest en la etiqueta de la aplicación]

private ArrayList<Class> runningActivities = new ArrayList<>();
  1. Y agregue los siguientes métodos públicos para acceder y modificar esta lista.

    public void addActivityToRunningActivityies (Class cls) {
    if (!runningActivities.contains(cls)) runningActivities.add(cls);
    }
    
    public void removeActivityFromRunningActivities (Class cls) {
    if (runningActivities.contains(cls)) runningActivities.remove(cls);
    }
    
    public boolean isActivityInBackStack (Class cls) {
    return runningActivities.contains(cls);
    }
  2. En su BaseActivity, donde todas las actividades lo extienden, anule los métodos onCreate y onDestroy para que pueda agregar y eliminar actividades de la pila posterior de la siguiente manera.

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    ((MyApplicationClass)getApplication()).addActivityToRunningActivityies
    (this.getClass());
    }
    
    @Override
    protected void onDestroy() {
    super.onDestroy();
    
    ((MyApplicationClass)getApplication()).removeActivityFromRunningActivities
    (this.getClass());
    }
  3. Finalmente, si desea verificar si la actividad está en la pila posterior o no, simplemente llame a esta función esActivityInBackStack.

Por ejemplo: quiero verificar si HomeActivity está en la pila posterior o no:

if (((MyApplicationClass) 
getApplication()).isActivityInBackStack(HomeActivity.class)) {
       // Activity is in the back stack
    } else {
       // Activity is not in the back stack
    }
Hagar Magdy
fuente
0
public static boolean isActivityActive(Activity activity) {
    return !activity.isFinishing() &&
            (SDK_INT < JELLY_BEAN_MR1 || !activity.isDestroyed());
}
Ahamadullah Saikat
fuente
-1

Esto funciona si no tienes la misma actividad en primer plano. Si abres desde la notificación no funciona, hice algunos ajustes y vine con esto:

public static boolean ativo = false;
public static int counter = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
    counter++;
}

@Override
protected void onStart() {
    super.onStart();
    ativo = true;
}

@Override
protected void onStop() {
    super.onStop();
    if (counter==1) ativo = false;
}

@Override
protected void onDestroy() {
    counter--;
    super.onDestroy();
}

Eso funciona para mí con varias actividades abiertas al mismo tiempo.

Simao Coutinho
fuente