Android: jak sprawdzić, czy aktywność jest aktywna?

152

Czy istnieje prosty sposób ustalenia, czy dana czynność jest aktywna, czy nie? Chcę robić pewne rzeczy w zależności od tego, która aktywność jest aktywna. na przykład:

if(activityrunning == activity1)
//do this
else if (activityrunning == activity2)
//do something else
user560571
źródło
Aby sprawdzić, czy działanie jest uruchomione, czy nie, możesz przejść przez tę odpowiedź: stackoverflow.com/a/39079627/4531507
Rahul Sharma

Odpowiedzi:

227

Możesz użyć staticzmiennej w ramach działania.

class MyActivity extends Activity {
     static boolean active = false;

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

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

Jedynym problemem jest to, że jeśli używasz go w dwóch działaniach, które są ze sobą powiązane, to onStoppierwsza jest czasami wywoływana po onStartdrugiej. Więc jedno i drugie może być prawdą w skrócie.

W zależności od tego, co próbujesz zrobić (zaktualizować bieżącą aktywność z usługi?). Możesz po prostu zarejestrować statyczny odbiornik w usłudze w swojej onStartmetodzie działania , a właściwy odbiornik będzie dostępny, gdy usługa będzie chciała zaktualizować interfejs użytkownika.

silikonowy Eagle
źródło
5
Ktoś zwrócił mi uwagę na to, że… Preferowanie współdzielenia powinno być preferowane zamiast zmiennej statycznej z powodu problemów z wyciekiem pamięci.
Ayush Goyal
13
Co się stanie, jeśli są prowadzone różne zajęcia tej samej klasy? A jeśli przedłużasz MyActivitysię MyChildactivityi chcesz sprawdzić, czy dziecko jest aktywne?
Mister Smith
2
W zależności od definicji „uruchomionego” możesz chcieć zmienić stan zmiennej w onResume i onPause ....
G. Blake Meike
5
To wcale nie jest dobre rozwiązanie. Powiedzmy, że Twoje działanie wywołuje fragment, na przykład fragment będzie nad działaniem, ale działanie nie będzie wywoływać funkcji onPause, a jeśli zamkniesz fragment onStop, onStart lub inne metody cyklu życia również nie zostaną wywołane. Najlepszym rozwiązaniem jest sprawdzenie w klasie Application widoczności, jak opisano tutaj: stackoverflow.com/questions/18038399/ ...
portfoliobuilder
6
Jeśli polecisz statykę, dostaniesz ode mnie -1
Matei Suica
52

Zdaję sobie sprawę, że ten problem jest dość stary, ale myślę, że nadal warto podzielić się moim rozwiązaniem, ponieważ może być przydatne dla innych.

To rozwiązanie nie było dostępne przed wydaniem składników architektury systemu Android.

Aktywność jest przynajmniej częściowo widoczna

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

Aktywność jest na pierwszym planie

getLifecycle().getCurrentState().isAtLeast(RESUMED)
malinjir
źródło
3
getLifecycle (). getCurrentState (). isAtLeast (Lifecycle.State.RESUMED)
Radhey
43

Myślę, że jest to bardziej jasne:

  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
źródło
2
Staram się unikać tworzenia zmiennych tymczasowych przed pętlą „for”; for (zadanie RunningTaskInfo: ActivityManager.getRunningTasks (Integer.MAX_VALUE)) {...
mikebabcock
Jak mogę wywołać tę funkcję?
Behzad
1
Jak zwykle, czy metoda, którą możesz wywołać w swojej klasie jako „funkcja”, czy potrzebujesz przykładu?
Xenione
10
From developer.android.com/reference/android/app/… „To nigdy nie powinno być używane do podstawowej logiki aplikacji, takiej jak wybieranie między różnymi zachowaniami na podstawie informacji tutaj znalezionych. Takie zastosowania nie są obsługiwane i prawdopodobnie zepsują w przyszłości."
joe_deniable
15
Od poziomu interfejsu API 21 (Android 5.0 Lollipop) ta metoda jest przestarzała.
AxeEffect
30

Opcją bez użycia żadnej zmiennej pomocniczej jest:

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

gdzie aktywność to np .: this lub getActivity ().

Wartość zwracana przez to wyrażenie zmienia się w onStart () / onStop (), czyli zdarzeniach, które rozpoczynają / kończą wyświetlanie układu działania na telefonie.

GaRRaPeTa
źródło
16
dlaczego nie używać jsut Activity#getWindow().getDecorView().isShown()?
Gianluca P.
24

Użyłem MyActivity.class i metody getCanonicalName i otrzymałem odpowiedź.

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
źródło
1
Jak wspomniano wcześniej, używanie go może nie być dobrym pomysłem, getRunningTasks()ponieważ zostało wycofane: androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/ ...
Vitalii Dmitriev
21

O wiele lepszy sposób niż używanie zmiennej statycznej i śledzenie OOP

Shared Preferencesmoże być używany do współdzielenia zmiennych z innymi activitiesi usługami z jednegoapplication

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

    }
}

Użyj wspólnych preferencji. Ma najbardziej wiarygodne informacje o stanie, mniej problemów z przełączaniem / niszczeniem aplikacji, oszczędza nam pytania o kolejne pozwolenie i daje nam większą kontrolę nad decydowaniem, kiedy nasza aktywność jest najważniejsza. zobacz szczegóły tutaj abd tutaj także

Zar E Ahmer
źródło
Dzięki. Ale czy onResume też jest potrzebny bracie?
1
To zależy od tego, co rozumiesz jako aktywny. Zgodnie z moim kodem, Aktywność jest na stosie, a następnie jest aktywna. A jeśli chcesz obsługiwać widoczne lub nie, możesz użyć onResume
Zar E Ahmer
19
To się psuje, gdy aktywność zostaje zabita bez wezwaniaonStop()
Marcel Bro
3
Co się stanie, jeśli aplikacja ulegnie awarii?
ucMedia
1
To bardzo niebezpieczne „rozwiązanie”.
Firzen
9

To jest kod do sprawdzania, czy dana usługa jest uruchomiona. Jestem prawie pewien, że może to działać również dla działania, o ile zmienisz getRunningServices za pomocą getRunningAppProcesses () lub getRunningTasks (). Zajrzyj tutaj http://developer.android.com/reference/android/app/ActivityManager.html#getRunningAppProcesses ()

Zmień odpowiednio Stałe.PACKAGE i Stałe.BACKGROUND_SERVICE_CLASS

    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
źródło
1
Pamiętaj jednak, że łącze, które podajesz, stwierdza: „ta metoda jest przeznaczona tylko do debugowania lub tworzenia interfejsu użytkownika do zarządzania procesami”.
joe_deniable
Funkcja getRunningTasks jest teraz przestarzała.
Adi
5

Jest o wiele łatwiejszy sposób niż wszystko powyżej, a to podejście nie wymaga użycia android.permission.GET_TASKSw manifeście ani nie wskazuje kwestii warunków wyścigu lub wycieków pamięci w przyjętej odpowiedzi.

  1. Utwórz zmienną STATIC w głównym działaniu. Static umożliwia innym działaniom otrzymywanie danych z innego działania. onPause()ustawić tę zmienną false , onResumea onCreate()ustawiona zmienna ta prawdziwa .

    private static boolean mainActivityIsOpen;
  2. Przypisz metody pobierające i ustawiające dla tej zmiennej.

    public static boolean mainActivityIsOpen() {
        return mainActivityIsOpen;
    }
    
    public static void mainActivityIsOpen(boolean mainActivityIsOpen) {
        DayView.mainActivityIsOpen = mainActivityIsOpen;
    }
  3. A potem z innej działalności lub Usługi

    if (MainActivity.mainActivityIsOpen() == false)
    {
                    //do something
    }
    else if(MainActivity.mainActivityIsOpen() == true)
    {//or just else. . . ( or else if, does't matter)
            //do something
    }
coolcool1994
źródło
3
Czy chcesz powiedzieć, że używanie metod akcesorów jest lepsze niż używanie surowych publicznych zmiennych statycznych?
IgorGanapolsky
1
W Javie lepiej jest używać metod ustawiających i pobierających, aby zachować prywatność zmiennych. Uważam jednak, że w Androidzie powszechny jest bezpośredni dostęp do zmiennych publicznych ...
Stephen,
11
Nie ma sensu mieć publicznego ustawiacza, ponieważ stan aktywności powinien być obsługiwany tylko przez samą czynność. Powinieneś trzymać się konwencji nazewnictwa java: isActivityOpen byłoby poprawną metodą pobierającą. Również użycie if boolean == true jest zbędne. Poza tym najlepszym podejściem jest delegowanie zarządzania państwowego do tej działalności.
Lisandro
8
dlatego powinieneś pilniej uczęszczać na kursy @coolcool;)
Jerec TheSith
1
A co, jeśli masz uruchomionych wiele wystąpień działania?
nickmartens1980
5
if(!activity.isFinishing() && !activity.isDestroyed())

Z oficjalnych dokumentów:

Aktywność # isFinishing ()

Sprawdź, czy ta czynność jest w trakcie kończenia, ponieważ wywołałeś na niej finish () lub ktoś inny zażądał jej zakończenia. Jest to często używane w onPause () do określenia, czy czynność jest po prostu wstrzymywana, czy całkowicie kończy.

Aktywność # isDestroyed ()

Zwraca wartość true, jeśli ostatnie wywołanie onDestroy () zostało wykonane w Activity, więc ta instancja jest teraz martwa.

Codelicious
źródło
4

dzięki kkudi! Udało mi się dostosować Twoją odpowiedź do pracy w zadaniu… oto, co zadziałało w mojej aplikacji…

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

ten przykład da ci wartość true lub false, jeśli topActivity pasuje do tego, co robi użytkownik. Więc jeśli aktywność, którą sprawdzasz, nie jest wyświetlana (tj. Jest onPause), nie otrzymasz dopasowania. Aby to zrobić, musisz dodać uprawnienie do swojego manifestu.

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

Mam nadzieję, że to było pomocne!

alyon2002
źródło
1
To pozwolenie na używanie zostało wycofane na poziomie API 21. developer.android.com/reference/android/ ...
Guy West,
2
Głosuj w dół, aby uzyskać dostęp do najważniejszych działań (usługi [i] .topActivity) .Minimalny poziom API Q .Poniżej to nie zadziała.
Debasish Ghosh
4

Myślę, że zaakceptowana odpowiedź jest okropnym sposobem radzenia sobie z tym.

Nie wiem, jaki jest przypadek użycia, ale proszę rozważyć metodę chronioną w klasie bazowej

@protected
void doSomething() {
}

i nadpisz go w klasie pochodnej.

Gdy wystąpi zdarzenie, po prostu wywołaj tę metodę w klasie bazowej. Wtedy poradzi sobie z tym właściwa „aktywna” klasa. Klasa sama może wtedy sprawdzić, czy tak nie jestPaused() .

Jeszcze lepiej, użyj magistrali zdarzeń, takiej jak GreenRobot , Square , ale ta jest przestarzała i sugeruje użycie RxJava

Chłopak
źródło
2

Użyłem czeku if (!a.isFinishing())i wydaje mi się, że robi to, czego potrzebuję. ajest instancją działania. Czy to jest niepoprawne? Dlaczego nikt tego nie próbował?

lxknvlk
źródło
2

co powiesz na activity.isFinishing()

Ambareesh B
źródło
To nie jest dobre rozwiązanie, ponieważ Finishing wskazuje, czy jakaś aktywność jest w trakcie zabijania.
VelocityPulse
2

ActivityLifecycleCallbacks to świetny sposób na śledzenie wszystkich działań w aplikacji:

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

Stan aktywności:

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

Rozszerz klasę Application i podaj jej odwołanie w pliku manifestu systemu 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;
}
}

Sprawdź gdziekolwiek z Aktywności, aby sprawdzić status innej aktywności

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
źródło
1

Nie jestem pewien, czy jest to „właściwy” sposób „robienia rzeczy”.
Jeśli nie ma sposobu API, aby rozwiązać (lub a) pytanie, niż powinieneś pomyśleć, być może robisz coś źle i zamiast tego czytasz więcej dokumentów itp.
(Jak rozumiem, zmienne statyczne są często niewłaściwym sposobem w Androidzie. Przyczyna mógłby działać, ale na pewno będą przypadki, kiedy nie zadziała [na przykład w produkcji, na milionach urządzeń]).
Dokładnie w twoim przypadku proponuję zastanowić się, dlaczego musisz wiedzieć, czy inna aktywność jest aktywna? .. możesz rozpocząć inną aktywność, aby uzyskać wynik, aby uzyskać jej funkcjonalność. Lub możesz wyprowadzić klasę, aby uzyskać jej funkcjonalność i tak dalej.
Z poważaniem.

user2399321
źródło
1

Jeśli interesuje Cię stan cyklu życia konkretnej instancji działania, rozwiązanie Siliconeagle wygląda poprawnie, z tym wyjątkiem, że nowa zmienna „aktywna” powinna być zmienną instancji, a nie statyczną.

Jonathan Taylor
źródło
1

Użyj zamówionej transmisji. Zobacz http://android-developers.blogspot.nl/2011/01/processing-ordered-broadcasts.html

W swojej działalności zarejestruj odbiorcę w onStart, wyrejestruj się z onStop. Teraz, gdy na przykład usługa musi obsłużyć coś, co mogłoby być w stanie zrobić lepiej, wyślij z usługi zamówioną transmisję (z domyślną obsługą w samej usłudze). Możesz teraz odpowiedzieć w działaniu, gdy jest ono uruchomione. Usługa może sprawdzić dane wyników, aby sprawdzić, czy transmisja została obsłużona, a jeśli nie, podjąć odpowiednie działania.

nickmartens1980
źródło
1

Oprócz zaakceptowanej odpowiedzi , jeśli masz wiele wystąpień działania, możesz zamiast tego użyć licznika:

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
źródło
brak „s” i „; (średnik)” w wierszu powrotu.
Ali_dev,
1

Czy próbowałeś..

    if (getActivity() instanceof NameOfYourActivity){
        //Do something
    }
E.Mathew
źródło
0

Znalazłem łatwe obejście tego kodu

@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
źródło
0

Użyj zmiennej isActivity, aby sprawdzić, czy aktywność jest aktywna, czy nie.

private boolean activityState = true;

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

Następnie sprawdź

if(activityState){
//add your code
}
Faran Tariq
źródło
0

Jeśli chcesz sprawdzić, czy aktywność znajduje się na tylnym stosie, wykonaj kolejne kroki. 1. Zadeklarowano ArrayList w klasie aplikacji [klasa aplikacji jest zdefiniowana w pliku mainfest w tagu aplikacji]

private ArrayList<Class> runningActivities = new ArrayList<>();
  1. Dodaj następujące metody publiczne, aby uzyskać dostęp do tej listy i zmodyfikować ją.

    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. W Twoim BaseActivity, gdzie wszystkie działania go rozszerzają, zastąp metody onCreate i onDestroy, aby można było dodawać i usuwać działania z zaplecza w następujący sposób.

    @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. Na koniec, jeśli chcesz sprawdzić, czy aktywność jest na tylnym stosie, czy nie, po prostu wywołaj tę funkcję isActivityInBackStack.

Np .: chcę sprawdzić, czy HomeActivity znajduje się na tylnym stosie, czy nie:

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

To działa, jeśli nie masz tej samej aktywności na pierwszym planie. Jeśli otworzysz z powiadomienia nie działa, wprowadziłem pewne poprawki i przyszedłem z tym:

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

U mnie to działa, gdy jednocześnie jest otwartych kilka działań.

Simao Coutinho
źródło