Android: come posso verificare se l'attività è in esecuzione?


152

Esiste un modo semplice per determinare se una determinata attività è attiva o no? Voglio fare determinate cose in base all'attività attiva. per esempio:

if(activityrunning == activity1)
//do this
else if (activityrunning == activity2)
//do something else

Per verificare se un'attività è in esecuzione o meno, è possibile passare attraverso questa risposta: stackoverflow.com/a/39079627/4531507
Rahul Sharma,

Risposte:


227

È possibile utilizzare una staticvariabile all'interno dell'attività.

class MyActivity extends Activity {
     static boolean active = false;

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

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

L'unico gotcha è che se lo usi in due attività che si collegano tra loro onStop, il primo viene talvolta chiamato dopo il onStartsecondo. Quindi entrambi potrebbero essere veri brevemente.

A seconda di ciò che si sta tentando di fare (aggiornare l'attività corrente da un servizio?). Puoi semplicemente registrare un listener statico nel servizio nel tuo onStartmetodo di attività , quindi il listener corretto sarà disponibile quando il tuo servizio desidera aggiornare l'interfaccia utente.


5
Qualcuno mi ha fatto notare che ... Il riferimento condiviso dovrebbe essere preferito a una variabile statica a causa di problemi di perdita di memoria.
Ayush Goyal,

13
E se ci sono diverse attività della stessa classe in esecuzione? Cosa succede se si estende MyActivitycon MyChildactivitye si desidera verificare se il bambino è attivo?
Mister Smith,

2
A seconda della definizione di "corsa", potresti voler cambiare lo stato della variabile in onResume e onPause ....
G. Blake Meike,

5
Questa soluzione non è affatto una buona soluzione. Diciamo che la tua attività chiama un frammento, ad esempio, il frammento sarà sopra l'attività ma l'attività non chiamerà onPause, e se chiudi il frammento onStop, onStart o qualsiasi altro metodo del ciclo di vita non verrà nemmeno chiamato. La migliore soluzione è quella di verificare nella tua classe di applicazione la visibilità come descritto qui: stackoverflow.com/questions/18038399/…
portfoliobuilder

6
Se mi consigli di statica, ricevi un -1 da me
Matei Suica,

52

Mi rendo conto che questo problema è piuttosto vecchio, ma penso che valga la pena condividere la mia soluzione in quanto potrebbe essere utile per gli altri.

Questa soluzione non era disponibile prima del rilascio di Android Architecture Components.

L'attività è almeno parzialmente visibile

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

L'attività è in primo piano

getLifecycle().getCurrentState().isAtLeast(RESUMED)

3
getLifecycle (). getCurrentState (). isAtLeast (Lifecycle.State.RESUMED)
Radhey,

43

Penso più chiaro così:

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

2
Cerco di evitare di creare variabili temporanee prima di un ciclo 'for'; per (attività RunningTaskInfo: ActivityManager.getRunningTasks (Integer.MAX_VALUE)) {...
mikebabcock

Come posso chiamare questa funzione?
Behzad,

1
come al solito, è un metodo che puoi chiamare all'interno della tua classe come 'funzione', hai bisogno di un esempio?
Xenione,

10
Da developer.android.com/reference/android/app/… "Questo non dovrebbe mai essere usato per la logica di base in un'applicazione, come decidere tra comportamenti diversi in base alle informazioni che si trovano qui. Tali usi non sono supportati e probabilmente si romperanno nel futuro."
joe_deniable

15
A partire dal livello API 21 (Android 5.0 Lollipop) questo metodo è stato deprecato.
AxeEffect,

30

Un'opzione senza usare alcuna variabile ausiliaria è:

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

dove attività è fe: this o getActivity ().

Il valore restituito da questa espressione cambia in onStart () / onStop (), che sono gli eventi che iniziano / interrompono mostrando il layout dell'attività sul telefono.


16
perché non usare jsut Activity#getWindow().getDecorView().isShown()?
Gianluca P.

24

Ho usato il metodo MyActivity.class e getCanonicalName e ho ottenuto la risposta.

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

1
Come accennato in precedenza, potrebbe non essere una buona idea usare getRunningTasks()come era deprecato: androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/…
Vitalii Dmitriev

21

Modo molto migliore rispetto all'utilizzo di una variabile statica e alla successiva OOP

Shared Preferencespuò essere utilizzato per condividere variabili con altri activitiese servizi da 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 le preferenze condivise. Ha le informazioni sullo stato più affidabili, meno problemi di cambio / eliminazione delle applicazioni, ci salva per chiedere ancora un'altra autorizzazione e ci dà un maggiore controllo per decidere quando la nostra attività è effettivamente la più alta. vedi dettagli qui abd anche qui


Grazie. Ma onResume serve anche fratello?

1
Dipende da cosa capisci per attivo. Secondo il mio codice, l'attività è nello stack quindi è attiva. E se vuoi gestire il visibile o no, puoi usare onResume
Zar E Ahmer,

19
Questo si interrompe quando l'attività viene uccisa senza chiamareonStop()
Marcel Bro

3
Cosa succede se l'app si arresta in modo anomalo?
ucMedia,

1
Questa è una "soluzione" molto pericolosa.
Firzen,

9

Questo è il codice per verificare se un particolare servizio è in esecuzione. Sono abbastanza sicuro che possa funzionare anche per un'attività purché cambi getRunningServices con getRunningAppProcesses () o getRunningTasks (). Dai un'occhiata qui http://developer.android.com/reference/android/app/ActivityManager.html#getRunningAppProcesses ()

Cambia Costanti.PACKAGE e Costanti.BACKGROUND_SERVICE_CLASS di conseguenza

    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;

}

1
Tuttavia, tenere presente che il collegamento fornito indica "questo metodo è destinato esclusivamente al debug o alla creazione di un'interfaccia utente di gestione dei processi rivolta agli utenti".
joe_deniable,

getRunningTasks è ora obsoleto.
Adi,

5

C'è un modo molto più semplice di tutto quanto sopra e questo approccio non richiede l'uso di android.permission.GET_TASKSmanifest, né è stato segnalato il problema delle condizioni di gara o delle perdite di memoria nella risposta accettata.

  1. Crea una variabile STATICA nell'attività principale. Statico consente ad altre attività di ricevere i dati da un'altra attività. onPause()impostare questa variabile falso , onResumee onCreate()impostare questa variabile vero .

    private static boolean mainActivityIsOpen;
  2. Assegna getter e setter di questa variabile.

    public static boolean mainActivityIsOpen() {
        return mainActivityIsOpen;
    }
    
    public static void mainActivityIsOpen(boolean mainActivityIsOpen) {
        DayView.mainActivityIsOpen = mainActivityIsOpen;
    }
  3. E poi da un'altra attività o servizio

    if (MainActivity.mainActivityIsOpen() == false)
    {
                    //do something
    }
    else if(MainActivity.mainActivityIsOpen() == true)
    {//or just else. . . ( or else if, does't matter)
            //do something
    }

3
Stai dicendo che usare metodi di accesso è meglio che usare variabili statiche pubbliche non elaborate?
IgorGanapolsky,

1
In Java è meglio usare setter e getter per mantenere private le variabili. Tuttavia, credo che in Android sia comune accedere direttamente alle variabili pubbliche ...
Stephen

11
Non ha senso avere un setter pubblico poiché lo stato dell'attività dovrebbe essere gestito solo dall'attività stessa. È necessario attenersi alle convenzioni di denominazione Java: isActivityOpen sarebbe un metodo getter corretto. Anche l'utilizzo se booleano == vero è ridondante. Inoltre, delegare la gestione statale all'attività è l'approccio migliore.
Lisandro,

8
ecco perché avresti dovuto frequentare i tuoi corsi più diligentemente @coolcool;)
Jerec TheSith

1
E se hai più istanze dell'attività in esecuzione?
nickmartens1980

5
if(!activity.isFinishing() && !activity.isDestroyed())

Dai documenti ufficiali:

Attività # isFinishing ()

Verifica se questa attività è in fase di completamento, sia perché hai chiamato finish () o se qualcun altro ha richiesto che sia terminata. Questo è spesso usato in onPause () per determinare se l'attività è semplicemente in pausa o completamente terminata.

Attività # isDestroyed ()

Restituisce vero se l'ultima chiamata onDestroy () è stata effettuata sull'attività, quindi questa istanza è ora morta.


4

grazie kkudi! Sono stato in grado di adattare la tua risposta al lavoro per un'attività ... ecco cosa ha funzionato nella mia app ..

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

questo esempio ti darà un vero o falso se topActivity corrisponde a ciò che l'utente sta facendo. Quindi se l'attività per cui stai verificando non viene visualizzata (ovvero è onPause), non otterrai una corrispondenza. Inoltre, per fare ciò devi aggiungere l'autorizzazione al tuo manifest ..

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

Spero sia stato utile!


1
Questo permesso d'uso è stato deprecato nel livello API 21. developer.android.com/reference/android/…
Guy West

2
Votazione dell'annswer perché si accede alle attività principali (servizi [i] .topActivity) minimo livello API Q. Sotto che non funzionerà.
Debasish Ghosh

4

Penso che la risposta accettata sia un modo terribile di gestirlo.

Non so quale sia il caso d'uso, ma per favore considera un metodo protetto nella classe base

@protected
void doSomething() {
}

e sovrascriverlo nella classe derivata.

Quando si verifica l'evento, basta chiamare questo metodo nella classe base. La classe "attiva" corretta la gestirà quindi. La classe stessa può quindi verificare se non lo è Paused().

Meglio ancora, usa un bus di eventi come GreenRobot's , Square's , ma quello è deprecato e suggerisce di usare RxJava


2

Ho usato un assegno if (!a.isFinishing())e sembra fare quello di cui ho bisogno. aè l'istanza dell'attività. È errato? Perché nessuno ha provato questo?



2

ActivityLifecycleCallbacks è un ottimo modo per tenere traccia di tutte le attività in App:

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

Estendi la classe Application e fornisci il riferimento nel file manifest di 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;
}
}

Seleziona ovunque Attività per lo stato di altre attività:

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


1

Non sono sicuro che sia un modo "corretto" di "fare le cose".
Se non esiste un modo API per risolvere la (o una) domanda di quanto dovresti pensare un po ', forse stai facendo qualcosa di sbagliato e leggi più documenti invece ecc.
(Come ho capito, le variabili statiche sono un modo comunemente sbagliato in Android. potrebbe funzionare, ma ci saranno sicuramente casi in cui non funzionerà [ad esempio, in produzione, su milioni di dispositivi]).
Esattamente nel tuo caso ti suggerisco di pensare perché devi sapere se un'altra attività è viva? .. puoi iniziare un'altra attività per ottenere il risultato per ottenere la sua funzionalità. Oppure puoi derivare la classe per ottenere la sua funzionalità e così via.
I migliori saluti.


1

Se sei interessato allo stato del ciclo di vita dell'istanza specifica dell'attività, la soluzione di siliconeagle sembra corretta, tranne per il fatto che la nuova variabile "attiva" dovrebbe essere una variabile di istanza piuttosto che statica.


1

Usa una trasmissione ordinata. Vedi http://android-developers.blogspot.nl/2011/01/processing-ordered-broadcasts.html

Nella tua attività, registra un ricevitore in onStart, annulla la registrazione in onStop. Ora, ad esempio, quando un servizio deve gestire qualcosa che l'attività potrebbe essere in grado di svolgere meglio, inviare una trasmissione ordinata dal servizio (con un gestore predefinito nel servizio stesso). Ora puoi rispondere all'attività quando è in esecuzione. Il servizio può controllare i dati dei risultati per vedere se la trasmissione è stata gestita e, in caso contrario, intraprendere le azioni appropriate.


1

Oltre alla la risposta accettata , se si dispone di più istanze di attività, è possibile utilizzare un contatore, invece:

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

manca "s" e "; (punto e virgola)" nella riga di ritorno.
Ali_dev,

1

Hai provato..

    if (getActivity() instanceof NameOfYourActivity){
        //Do something
    }

0

Ho trovato una soluzione semplice con il seguente codice

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

0

Utilizzare la variabile isActivity per verificare se l'attività è attiva o meno.

private boolean activityState = true;

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

Quindi controlla

if(activityState){
//add your code
}

0

Se vuoi verificare se l'attività è nello stack posteriore, segui semplicemente i passaggi successivi. 1. Dichiarato un ArrayList nella tua classe di applicazione [La classe di applicazione è definita nel tuo file mainfest nel tag dell'applicazione]

private ArrayList<Class> runningActivities = new ArrayList<>();
  1. E aggiungi i seguenti metodi pubblici per accedere e modificare questo elenco.

    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. In BaseActivity, dove tutte le attività lo estendono, sovrascrivi i metodi onCreate e onDestroy in modo da poter aggiungere e rimuovere attività dallo stack posteriore come segue.

    @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. Infine, se si desidera verificare se l'attività si trova nello stack posteriore o non si chiama semplicemente questa funzione isActivityInBackStack.

Es: Voglio verificare se HomeActivity è nello stack posteriore oppure no:

if (((MyApplicationClass) 
getApplication()).isActivityInBackStack(HomeActivity.class)) {
       // Activity is in the back stack
    } else {
       // Activity is not in the back stack
    }

0
public static boolean isActivityActive(Activity activity) {
    return !activity.isFinishing() &&
            (SDK_INT < JELLY_BEAN_MR1 || !activity.isDestroyed());
}

-1

Questo funziona se non hai la stessa attività in primo piano. Se si apre dalla notifica non funziona, ho apportato alcune modifiche e sono arrivato con questo:

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

Questo funziona per me con diverse attività aperte contemporaneamente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.