Android: comment vérifier si l'activité est en cours?

152

Existe-t-il un moyen simple de déterminer si une certaine activité est active ou non? Je veux faire certaines choses en fonction de l'activité active. par exemple:

if(activityrunning == activity1)
//do this
else if (activityrunning == activity2)
//do something else
user560571
la source
Pour vérifier si une activité est en cours d'exécution ou non, vous pouvez passer par cette réponse: stackoverflow.com/a/39079627/4531507
Rahul Sharma

Réponses:

227

Vous pouvez utiliser une staticvariable dans l'activité.

class MyActivity extends Activity {
     static boolean active = false;

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

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

Le seul problème est que si vous l'utilisez dans deux activités qui se lient l'une à l'autre onStop, la première est parfois appelée après la onStartseconde. Les deux pourraient donc être vrais brièvement.

En fonction de ce que vous essayez de faire (mettre à jour l'activité actuelle d'un service?). Vous pouvez simplement enregistrer un écouteur statique dans le service dans votre onStartméthode d' activité , puis l'écouteur approprié sera disponible lorsque votre service souhaite mettre à jour l'interface utilisateur.

siliconeagle
la source
5
Quelqu'un m'a fait remarquer que ... La préférence partagée devrait être préférée à une variable statique en raison de problèmes de fuite de mémoire.
Ayush Goyal
13
Et s'il y avait différentes activités de la même classe en cours? Que faire si vous prolongez MyActivityavec MyChildactivityet que vous souhaitez vérifier si l'enfant est actif?
Mister Smith le
2
En fonction de votre définition de «running», vous voudrez peut-être changer l'état de la variable dans onResume et onPause ....
G. Blake Meike
5
Cette solution n'est pas du tout une bonne solution. Disons que votre activité appelle un fragment, par exemple, le fragment sera sur l'activité mais l'activité n'appellera pas onPause, et si vous fermez le fragment onStop, onStart, ou toute autre méthode de cycle de vie ne sera pas appelée non plus. La meilleure solution est de vérifier dans votre classe Application la visibilité comme décrit ici: stackoverflow.com/questions/18038399/...
portfoliobuilder
6
Si vous recommandez la statique, vous obtenez un -1 de ma part
Matei Suica
53

Je me rends compte que ce problème est assez ancien, mais je pense qu'il vaut toujours la peine de partager ma solution car elle pourrait être utile à d'autres.

Cette solution n'était pas disponible avant la sortie des composants d'architecture Android.

L'activité est au moins partiellement visible

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

L'activité est au premier plan

getLifecycle().getCurrentState().isAtLeast(RESUMED)
malinjir
la source
3
getLifecycle (). getCurrentState (). isAtLeast (Lifecycle.State.RESUMED)
Radhey
43

Je pense plus clair comme ça:

  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
la source
2
J'essaie d'éviter de créer des variables temporaires avant une boucle «for»; pour (tâche RunningTaskInfo: ActivityManager.getRunningTasks (Integer.MAX_VALUE)) {...
mikebabcock
Comment puis-je appeler cette fonction?
Behzad
1
comme d'habitude, une méthode que vous pouvez appeler dans votre classe en tant que «fonction» avez-vous besoin d'un exemple?
Xenione
10
From developer.android.com/reference/android/app/... "Cela ne doit jamais être utilisé pour la logique de base d'une application, comme le choix entre différents comportements en fonction des informations trouvées ici. De telles utilisations ne sont pas prises en charge et risquent de ne pas fonctionner. A l'avenir."
joe_deniable
15
Depuis le niveau d'API 21 (Android 5.0 Lollipop), cette méthode est obsolète.
AxeEffect
30

Une option sans utiliser de variable auxiliaire est:

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

où l'activité est fe: this ou getActivity ().

La valeur renvoyée par cette expression change dans onStart () / onStop (), qui sont les événements qui démarrent / arrêtent montrant la disposition de l'activité sur le téléphone.

GaRRaPeTa
la source
16
pourquoi ne pas l'utiliser Activity#getWindow().getDecorView().isShown()?
Gianluca P.
24

J'ai utilisé MyActivity.class et la méthode getCanonicalName et j'ai obtenu une réponse.

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
la source
1
Comme mentionné précédemment, ce n'est peut-être pas une bonne idée à utiliser getRunningTasks()car il était obsolète: androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/…
Vitalii Dmitriev
21

Bien mieux que d'utiliser une variable statique et de suivre la POO

Shared Preferencespeut être utilisé pour partager des variables avec d'autres activitieset des services d'unapplication

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

    }
}

Utilisez les préférences partagées. Il a les informations d'état les plus fiables, moins de problèmes de changement / destruction d'application, nous évite de demander une autre autorisation et nous donne plus de contrôle pour décider quand notre activité est réellement la plus élevée. voir les détails ici abd ici aussi

Zar E Ahmer
la source
Merci. Mais onResume est-il également nécessaire bro?
1
Cela dépend de ce que vous entendez par actif. Selon mon code, l'activité est en pile puis elle est active. Et si vous voulez gérer visible ou non, vous pouvez utiliser onResume
Zar E Ahmer
19
Cela se rompt lorsque l'activité est tuée sans appeleronStop()
Marcel Bro
3
Que se passe-t-il si l'application plante?
ucMedia
1
C'est une «solution» très dangereuse.
Firzen le
9

Il s'agit d'un code permettant de vérifier si un service particulier est en cours d'exécution. Je suis assez sûr que cela peut fonctionner pour une activité aussi longtemps que vous changez getRunningServices avec getRunningAppProcesses () ou getRunningTasks (). Jetez un oeil ici http://developer.android.com/reference/android/app/ActivityManager.html#getRunningAppProcesses ()

Modifiez Constants.PACKAGE et Constants.BACKGROUND_SERVICE_CLASS en conséquence

    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
la source
1
Mais gardez à l'esprit que le lien que vous fournissez indique que "cette méthode est uniquement destinée au débogage ou à la création d'une interface utilisateur de gestion de processus destinée aux utilisateurs."
joe_deniable
getRunningTasks est désormais obsolète.
Adi
5

Il existe un moyen beaucoup plus simple que tout ce qui précède et cette approche ne nécessite pas l'utilisation de android.permission.GET_TASKSdans le manifeste, ni le problème des conditions de concurrence ou des fuites de mémoire souligné dans la réponse acceptée.

  1. Créez une variable STATIC dans l'activité principale. Statique permet à d'autres activités de recevoir les données d'une autre activité. onPause()définir cette variable fausse , onResumeet onCreate()définir cette variable vrai .

    private static boolean mainActivityIsOpen;
  2. Attribuez des getters et des setters à cette variable.

    public static boolean mainActivityIsOpen() {
        return mainActivityIsOpen;
    }
    
    public static void mainActivityIsOpen(boolean mainActivityIsOpen) {
        DayView.mainActivityIsOpen = mainActivityIsOpen;
    }
  3. Et puis à partir d'une autre activité ou service

    if (MainActivity.mainActivityIsOpen() == false)
    {
                    //do something
    }
    else if(MainActivity.mainActivityIsOpen() == true)
    {//or just else. . . ( or else if, does't matter)
            //do something
    }
coolcool1994
la source
3
Êtes-vous en train de dire qu'il est préférable d'utiliser des méthodes d'accesseur plutôt que d'utiliser des variables statiques publiques brutes?
IgorGanapolsky
1
En Java, il est préférable d'utiliser des setters et des getters pour garder vos variables privées. Cependant, je crois que dans Android, il est courant d'accéder directement aux variables publiques ...
Stephen
11
Cela n'a aucun sens d'avoir un setter public puisque l'état de l'activité ne doit être géré que par l'activité elle-même. Vous devez vous en tenir aux conventions de dénomination Java: isActivityOpen serait une méthode de lecture correcte. Utiliser également if boolean == true est redondant. En outre, déléguer la gestion de l'État à l'activité est la meilleure approche.
Lisandro
8
c'est pourquoi vous auriez dû suivre vos cours avec plus d'assiduité @coolcool;)
Jerec TheSith
1
Et si vous avez plusieurs instances de l'activité en cours d'exécution?
nickmartens1980
5
if(!activity.isFinishing() && !activity.isDestroyed())

À partir des documents officiels:

Activité # isFinishing ()

Vérifiez si cette activité est en train de se terminer, soit parce que vous avez appelé finish () dessus, soit parce que quelqu'un d'autre a demandé qu'elle se termine. Ceci est souvent utilisé dans onPause () pour déterminer si l'activité est simplement en pause ou complètement terminée.

Activité # isDestroyed ()

Renvoie true si le dernier appel à onDestroy () a été effectué sur l'activité, donc cette instance est maintenant morte.

Codelicious
la source
4

merci kkudi! J'ai pu adapter votre réponse pour travailler pour une activité ... voici ce qui a fonctionné dans mon application.

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

cet exemple vous donnera un vrai ou un faux si topActivity correspond à ce que fait l'utilisateur. Donc, si l'activité que vous recherchez n'est pas affichée (c'est-à-dire en pause), vous n'obtiendrez pas de correspondance. Pour ce faire, vous devez également ajouter l'autorisation à votre manifeste.

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

J'espère que cela a été utile!

alyon2002
la source
1
Cette autorisation d'utilisation est obsolète au niveau de l'API 21. developer.android.com/reference/android/…
Guy West
2
Downvote l'annswer parce que pour accéder à l'activité supérieure (services [i] .topActivity) nous minimisons le niveau d'API Q. Ci-dessous, cela ne fonctionnera pas.
Debasish Ghosh le
4

Je pense que la réponse acceptée est une manière terrible de gérer cela.

Je ne sais pas quel est le cas d'utilisation, mais veuillez considérer une méthode protégée dans la classe de base

@protected
void doSomething() {
}

et remplacez-le dans la classe dérivée.

Lorsque l'événement se produit, appelez simplement cette méthode dans la classe de base. La classe «active» correcte la gérera alors. La classe elle-même peut alors vérifier si ce n'est pas le cas Paused().

Mieux encore, utilisez un bus d'événements comme celui de GreenRobot , Square , mais celui-ci est obsolète et suggère d'utiliser RxJava

Garçon
la source
2

J'ai utilisé un chèque if (!a.isFinishing())et il semble faire ce dont j'ai besoin. aest l'instance d'activité. Est-ce incorrect? Pourquoi personne n'a essayé ça?

lxknvlk
la source
2

qu'en est-il de activity.isFinishing()

Ambareesh B
la source
Ce n'est pas une bonne solution car isFinishing indique s'il y a une activité dans un processus de mise à mort.
VelocityPulse
2

ActivityLifecycleCallbacks est un excellent moyen de suivre toutes les activités de l'application:

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

Étendez la classe Application et fournissez sa référence dans le fichier Manifest 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;
}
}

Vérifiez n'importe où à partir de l'activité pour le statut d'une autre activité:

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
la source
1

Je ne suis pas sûr que ce soit une «bonne» façon de «faire les choses».
S'il n'y a aucun moyen de l' API pour résoudre le (ou a) question que vous devriez réfléchir un peu, peut - être que vous faites quelque chose de mal et lire plus de docs à la place , etc.
(Comme je l' ai compris les variables statiques est une façon généralement mal dans Android. De la cause cela pourrait fonctionner, mais il y aura certainement des cas où cela ne fonctionnera pas [par exemple, en production, sur des millions d'appareils]).
Exactement dans votre cas, je suggère de réfléchir pourquoi avez-vous besoin de savoir si une autre activité est vivante? .. vous pouvez démarrer une autre activité pour que le résultat obtienne sa fonctionnalité. Ou vous pouvez dériver la classe pour obtenir ses fonctionnalités et ainsi de suite.
Meilleures salutations.

utilisateur2399321
la source
1

Si vous êtes intéressé par l'état du cycle de vie de l'instance spécifique de l'activité, la solution de siliconeagle semble correcte, sauf que la nouvelle variable "active" doit être une variable d'instance plutôt que statique.

Jonathan Taylor
la source
1

Utilisez une diffusion commandée. Voir http://android-developers.blogspot.nl/2011/01/processing-ordered-broadcasts.html

Dans votre activité, enregistrez un récepteur dans onStart, désinscrivez-vous dans onStop. Maintenant, lorsque, par exemple, un service doit gérer quelque chose que l'activité pourrait mieux faire, envoyez une diffusion ordonnée à partir du service (avec un gestionnaire par défaut dans le service lui-même). Vous pouvez maintenant répondre à l'activité lorsqu'elle est en cours d'exécution. Le service peut vérifier les données de résultat pour voir si la diffusion a été gérée et, dans le cas contraire, prendre les mesures appropriées.

nickmartens1980
la source
1

En plus de la réponse acceptée , si vous avez plusieurs instances de l'activité, vous pouvez utiliser un compteur à la place:

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
la source
"s" et "; (point virgule)" manquants dans la ligne de retour.
Ali_dev
1

As-tu essayé..

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

Trouvé une solution de contournement facile avec le code suivant

@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
la source
0

Utilisez la variable isActivity pour vérifier si l'activité est active ou non.

private boolean activityState = true;

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

Puis vérifier

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

Si vous voulez vérifier si l'activité est dans la pile arrière, suivez simplement les étapes suivantes. 1. Déclaré un ArrayList dans votre classe Application [La classe Application est définie dans votre fichier mainfest dans la balise application]

private ArrayList<Class> runningActivities = new ArrayList<>();
  1. Et ajoutez les méthodes publiques suivantes pour accéder et modifier cette liste.

    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. Dans votre BaseActivity, où toutes les activités l'étendent, remplacez les méthodes onCreate et onDestroy afin que vous puissiez ajouter et supprimer des activités de la pile arrière comme suit.

    @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. Enfin, si vous souhaitez vérifier si l'activité est dans la pile arrière ou non, appelez simplement cette fonction isActivityInBackStack.

Ex: je veux vérifier si le HomeActivity est dans la pile arrière ou non:

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

Cela fonctionne si vous n'avez pas la même activité au premier plan. Si vous ouvrez à partir de la notification ne fonctionne pas, j'ai fait quelques ajustements et je suis venu avec ceci:

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

Cela fonctionne pour moi avec plusieurs activités ouvertes en même temps.

Simao Coutinho
la source