Jak mogę sprawdzić, czy aplikacja na Androida działa na pierwszym planie?

83

Wykonuję powiadomienie na pasku stanu w mojej aplikacji na Androida, które jest wyzwalane przez c2dm. Nie chcę wyświetlać powiadomienia, jeśli aplikacja jest uruchomiona. Jak określić, czy aplikacja działa i znajduje się na pierwszym planie?

Andrew Thomas
źródło
To jest podobne pytanie ... chociaż wypróbowałem flagę onStart / onStop i nie działa. Nadal nie widzę różnicy między zatrzymaniem / uruchomieniem a wstrzymaniem / wznowieniem.
Andrew Thomas,
1
Powinieneś użyć tego rozwiązania: stackoverflow.com/questions/3667022/ ...
Informatic0re
Od API 16 istnieje prostszy sposób korzystania z ActivityManager.getMyMemoryState
Juozas Kontvainis
Ponieważ obsługuje bibliotekę w wersji 26, wystarczy wysłać zapytanie do ProcessLifecycleOwner, kiedy tylko chcesz. Sprawdź stackoverflow.com/a/52678290/6600000
Keivan Esbati

Odpowiedzi:

55

Utwórz zmienną globalną, taką jak private boolean mIsInForegroundMode;i przypisz falsewartość w onPause()i truewartość w onResume().

Przykładowy kod:

private boolean mIsInForegroundMode;

@Override
protected void onPause() {
    super.onPause();
    mIsInForegroundMode = false;
}

@Override
protected void onResume() {
    super.onResume();
    mIsInForegroundMode = true;
}

// Some function.
public boolean isInForeground() {
    return mIsInForegroundMode;
}
Wroclai
źródło
2
@MurVotema: Tak, jest. Ale możemy swobodnie przekazywać tę zmienną, np. Do preferencji lub bazy danych, ilekroć ma miejsce zmiana.
Wroclai
19
@Shelly Ale twoja zmienna często zmieniałaby się na True / False / True podczas przełączania działań w tej samej aplikacji. Oznacza to, że musisz mieć histerezę, aby naprawdę wykryć, kiedy Twoja aplikacja traci pierwszy plan.
Radu,
10
To nie jest najlepsze rozwiązanie. Sprawdź rozwiązanie @Gadenkan poniżej.
Felipe Lima
Działa w prostych scenariuszach, ale jeśli masz onActivityResult () na swoim działaniu, sprawy się komplikują. Chcę uruchomić usługę w tle wtedy i tylko wtedy, gdy wszystkie działania mojej aplikacji są w tle, a powyższe rozwiązanie jest niewystarczające.
Josh
1
@Tima Jeśli chcesz udostępnić go dla wszystkich działań, możesz utworzyć nową MyOwnActivity rozszerza AppCompatActivity ... Następnie wewnątrz MyOwnActivity nadpisuj obie opcje onResume () / onPause (), a na koniec rozszerz wszystkie działania aplikacji z MyOwnActivity zamiast AppCompatActivity. Problem rozwiązany. ; )
elliotching
112

Alternatywnie możesz sprawdzić, ActivityManagerjakie zadania są uruchomione według getRunningTasksmetody. Następnie sprawdź z pierwszym zadaniem (zadanie na pierwszym planie) na zwróconej Liście zadań, jeśli jest to Twoje zadanie.
Oto przykład kodu:

public Notification buildNotification(String arg0, Map<String, String> arg1) {

    ActivityManager activityManager = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> services = activityManager
            .getRunningTasks(Integer.MAX_VALUE);
    boolean isActivityFound = false;

    if (services.get(0).topActivity.getPackageName().toString()
            .equalsIgnoreCase(appContext.getPackageName().toString())) {
        isActivityFound = true;
    }

    if (isActivityFound) {
        return null;
    } else {
        // write your code to build a notification.
        // return the notification you built here
    }

}

I nie zapomnij dodać GET_TASKSuprawnienia w pliku manifest.xml , aby móc uruchomić getRunningTasks()metodę w powyższym kodzie:

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

p / s: Jeśli zgadzasz się w ten sposób, pamiętaj, że to uprawnienie jest teraz przestarzałe.

Gadenkan
źródło
24
Jeśli chcesz użyć tego kodu, nie zapomnij dodać <używa-pozwolenia android: name = "android.permission.GET_TASKS" />
Lakshmanan
13
Nitpicks: Wywołanie toString()ciągu zwróconego przez getPackageName()jest zbędne. Ponieważ interesuje nas tylko pierwsze zwrócone zadanie getRunningTasks(), możemy przejść 1zamiast Integer.MAX_VALUE.
Jonik
14
Uwaga: ta metoda jest przeznaczona tylko do debugowania i prezentowania interfejsów użytkownika do zarządzania zadaniami. Nie powinno to być nigdy używane w przypadku podstawowej logiki aplikacji, takiej jak podejmowanie decyzji dotyczących różnych zachowań na podstawie informacji znajdujących się tutaj. Takie zastosowania nie są obsługiwane i prawdopodobnie ulegną awarii w przyszłości. Na przykład, jeśli wiele aplikacji może aktywnie działać w tym samym czasie, przyjęte założenia dotyczące znaczenia danych tutaj dla celów przepływu sterowania będą nieprawidłowe.
Informatic0re
5
Niestety metoda getRunningTasks () jest przestarzała od czasu systemu Android L (API 20). Od wersji L ta metoda nie jest już dostępna dla aplikacji innych firm: wprowadzenie ostatnich zorientowanych na dokumenty oznacza, że ​​może ona spowodować wyciek informacji o osobie do dzwoniącego. W celu zapewnienia kompatybilności wstecznej nadal zwróci niewielki podzbiór swoich danych: przynajmniej własne zadania wywołującego i prawdopodobnie inne zadania, takie jak dom, o których wiadomo, że nie są wrażliwe.
Sam Lu
2
Przypuszczalnie jeśli pokazuje tylko zadania dzwoniącego, pierwsze zadanie i najważniejsza aktywność zawsze będą Twoje, co oznacza, że ​​zawsze zwróci to prawdziwy post-lollipop.
Mike Holler
46

To dość stary post, ale nadal dość aktualny. Powyższe przyjęte rozwiązanie może działać, ale jest błędne. Jak napisała Dianne Hackborn:

Te interfejsy API nie służą aplikacjom, na których mogą opierać swój przepływ interfejsu użytkownika, ale służą do wykonywania takich czynności, jak pokazywanie użytkownikowi uruchomionych aplikacji, menedżera zadań itp.

Tak, jest lista tych rzeczy przechowywana w pamięci. Jest to jednak wyłączone w innym procesie, zarządzanym przez wątki działające niezależnie od twojego i nie jest to coś, na co możesz liczyć (a) dostrzec na czas, aby podjąć właściwą decyzję lub (b) mieć spójny obraz do czasu powrotu. Ponadto decyzja o tym, do jakiej „następnej” czynności należy przejść, jest zawsze podejmowana w miejscu, w którym ma nastąpić zmiana, i dopiero w tym dokładnym punkcie (gdzie stan aktywności jest na krótko zablokowany, aby dokonać zmiany) właściwie wiem, co będzie dalej.

Nie ma gwarancji, że implementacja i zachowanie globalne pozostaną takie same w przyszłości.

Prawidłowym rozwiązaniem jest wdrożenie: ActivityLifeCycleCallbacks .

Zasadniczo wymaga to klasy aplikacji i można tam ustawić procedurę obsługi, aby zidentyfikować stan działań w aplikacji.

Vinay
źródło
7
Oto przykład, jak go używać baroqueworksdev.blogspot.com/2012/12/…
Kaloyan Roussev
2
Myślę, że to najlepsze rozwiązanie i prawdopodobnie nie zepsuje się w przyszłości. Ciekawe, dlaczego nie zebrał wystarczającej liczby głosów.
Rohan Kandwal
2
Jeśli napiszesz przykładowy kod, zdobędziesz więcej głosów, ponieważ niektórzy pomijają odpowiedzi bez przykładu ... ale to najlepsze rozwiązanie ...
Saman Salehi
czym różni się to od przesłaniania onPausei onResumemetody zastosowanej w zaakceptowanej odpowiedzi?
Saitama
24

Jak mówi Vinay, prawdopodobnie najlepszym rozwiązaniem (do obsługi nowszych wersji Androida, 14+) jest użycie ActivityLifecycleCallbacksw Applicationimplementacji klasy.

package com.telcel.contenedor.appdelegate;

import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;

/** Determines global app lifecycle states. 
 * 
 * The following is the reference of activities states:
 * 
 * The <b>visible</b> lifetime of an activity happens between a call to onStart()
 * until a corresponding call to onStop(). During this time the user can see the
 * activity on-screen, though it may not be in the foreground and interacting with 
 * the user. The onStart() and onStop() methods can be called multiple times, as 
 * the activity becomes visible and hidden to the user.
 * 
 * The <b>foreground</b> lifetime of an activity happens between a call to onResume()
 * until a corresponding call to onPause(). During this time the activity is in front
 * of all other activities and interacting with the user. An activity can frequently
 * go between the resumed and paused states -- for example when the device goes to
 * sleep, when an activity result is delivered, when a new intent is delivered -- 
 * so the code in these methods should be fairly lightweight. 
 * 
 * */
public class ApplicationLifecycleManager implements ActivityLifecycleCallbacks {

    /** Manages the state of opened vs closed activities, should be 0 or 1. 
     * It will be 2 if this value is checked between activity B onStart() and
     * activity A onStop().
     * It could be greater if the top activities are not fullscreen or have
     * transparent backgrounds.
     */
    private static int visibleActivityCount = 0;

    /** Manages the state of opened vs closed activities, should be 0 or 1
     * because only one can be in foreground at a time. It will be 2 if this 
     * value is checked between activity B onResume() and activity A onPause().
     */
    private static int foregroundActivityCount = 0;

    /** Returns true if app has foreground */
    public static boolean isAppInForeground(){
        return foregroundActivityCount > 0;
    }

    /** Returns true if any activity of app is visible (or device is sleep when
     * an activity was visible) */
    public static boolean isAppVisible(){
        return visibleActivityCount > 0;
    }

    public void onActivityCreated(Activity activity, Bundle bundle) {
    }

    public void onActivityDestroyed(Activity activity) {
    }

    public void onActivityResumed(Activity activity) {
        foregroundActivityCount ++;
    }

    public void onActivityPaused(Activity activity) {
        foregroundActivityCount --;
    }


    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
    }

    public void onActivityStarted(Activity activity) {
        visibleActivityCount ++;
    }

    public void onActivityStopped(Activity activity) {
        visibleActivityCount --;
    }
}

A w onCreate()metodzie aplikacji :

registerActivityLifecycleCallbacks(new ApplicationLifecycleManager());

Następnie ApplicationLifecycleManager.isAppVisible()lub ApplicationLifecycleManager.isAppInForeground()byłby używany do poznania pożądanego stanu.

htafoya
źródło
Będzie działać tylko z isAppVisible (). Jeśli zamkniesz aplikację, wyślij na pierwszy plan, nie przyniesie to żadnego efektu
AlwaysConfused
19

Od API 16 możesz to zrobić w ten sposób:

static boolean shouldShowNotification(Context context) {
    RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
    ActivityManager.getMyMemoryState(myProcess);
    if (myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
        return true;

    KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
    // app is in foreground, but if screen is locked show notification anyway
    return km.inKeyguardRestrictedInputMode();
}
Juozas Kontvainis
źródło
Wydajne rozwiązanie. Dzięki :)
dr Sajedul Karim,
Bardzo fajne rozwiązanie. Żadne uprawnienia nie są wymagane.
user3144836
Niesamowite! Używałem listy zadań, ale wymaga to POBIERZ ZADANIE ... naprawdę to doceniam!
hexagod
15

FYI, jeśli używasz rozwiązania Gadenkan (co jest świetne!), Nie zapomnij dodać

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

do manifestu.

bertz94
źródło
9
W Androidzie Lollipop to uprawnienie jest przestarzałe
Mussa
14

Lekko poprawiona wersja rozwiązania Gadenkana . Umieść to dowolne działanie lub może klasę bazową dla wszystkich swoich działań.

protected boolean isRunningInForeground() {
    ActivityManager manager = 
         (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> tasks = manager.getRunningTasks(1);
    if (tasks.isEmpty()) {
        return false;
    }
    String topActivityName = tasks.get(0).topActivity.getPackageName();
    return topActivityName.equalsIgnoreCase(getPackageName());
}

Aby móc dzwonić getRunningTasks(), musisz dodać to w AndroidManifest.xml:

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

Zwróć jednak uwagę na to, co ActivityManager.getRunningTasks() mówi Javadoc:

Uwaga: ta metoda jest przeznaczona tylko do debugowania i prezentowania interfejsów użytkownika do zarządzania zadaniami. Nie powinno to być nigdy używane w przypadku podstawowej logiki aplikacji, takiej jak podejmowanie decyzji dotyczących różnych zachowań na podstawie informacji znajdujących się tutaj. Takie zastosowania nie są obsługiwane i prawdopodobnie ulegną awarii w przyszłości.

Aktualizacja (luty 2015)

Zauważ, że getRunningTasks()został wycofany na poziomie API 21 !

Od LOLLIPOPtej pory ta metoda nie jest już dostępna dla aplikacji innych firm: wprowadzenie ostatnich zorientowanych na dokumenty oznacza, że ​​może ona spowodować wyciek informacji o osobie do dzwoniącego. W celu zapewnienia kompatybilności wstecznej nadal zwróci niewielki podzbiór swoich danych: przynajmniej własne zadania wywołującego i prawdopodobnie inne zadania, takie jak dom, o których wiadomo, że nie są wrażliwe.

Więc to, co napisałem wcześniej, jest jeszcze bardziej istotne:

W wielu przypadkach prawdopodobnie możesz znaleźć lepsze rozwiązanie. Na przykład robienie czegoś w onPause()i onResume()być może w BaseActivity dla wszystkich działań.

(W naszym przypadku nie chcieliśmy, aby działanie alarmowe w trybie offline było uruchamiane, jeśli nie jesteśmy na pierwszym planie, więc w BaseActivity onPause()po prostu wypisujemy się z RxJava Subscriptionnasłuchującego sygnału „poszedł offline”.)

Jonik
źródło
czy możesz wysłać kod RxJava, którego użyłeś? Chcę używać RxJava i nie chcę spędzać dużo czasu na nauce RxJava w tej chwili :(
MBH
@MBH: Używanie RxJava prawdopodobnie nie będzie zbyt owocne bez poświęcenia trochę czasu na zapoznanie się z podstawowymi pojęciami ... :-) W każdym razie, oto mały przykład .
Jonik
9

W odpowiedzi na odpowiedź Gadenkana potrzebowałem czegoś takiego, żebym mógł stwierdzić, czy moja aplikacja nie działa na pierwszym planie, ale potrzebowałem czegoś, co było szerokie na aplikację i nie wymagało ustawiania / wyłączania flag w całej aplikacji.

Kod Gadenkana trafił w sedno, ale nie był w moim własnym stylu i uważałem, że może być uporządkowany, więc w mojej aplikacji jest do tego skondensowany.

if (!context.getPackageName().equalsIgnoreCase(((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(1).get(0).topActivity.getPackageName()))
{
// App is not in the foreground
}

(Uwaga dodatkowa: możesz po prostu usunąć!, Jeśli chcesz, aby czek działał w drugą stronę)

Chociaż przy takim podejściu potrzebujesz GET_TASKSpozwolenia.

CrosseyeJack
źródło
3

Począwszy od wersji 26 biblioteki obsługi, możesz użyć ProcessLifecycleOwner do określenia bieżącego stanu aplikacji, po prostu dodaj ją do swoich zależności, jak opisano tutaj , na przykład:

dependencies {
    def lifecycle_version = "1.1.1"

    // ViewModel and LiveData
    implementation "android.arch.lifecycle:extensions:$lifecycle_version"
    // alternatively - Lifecycles only (no ViewModel or LiveData).
    //     Support library depends on this lightweight import
    implementation "android.arch.lifecycle:runtime:$lifecycle_version"
    annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" // use kapt for Kotlin
}

Teraz możesz zapytać, ProcessLifecycleOwnerkiedy chcesz sprawdzić stan aplikacji, na przykład, aby sprawdzić, czy aplikacja działa na pierwszym planie, wystarczy zrobić to:

 boolean isAppInForeground = ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
 if(!isAppInForeground)
    //Show Notification in status bar
Keivan Esbati
źródło
1
To jest właściwa odpowiedź. Wiele innych należy uznać za przestarzałe
11m0
Dla AndroidX Java użyj implementation 'androidx.lifecycle:lifecycle-process:2.2.0'w gradle projektu.
Jonathan
1

Na podstawie różnych odpowiedzi i komentarzy, oto bardziej wbudowana wersja, którą możesz dodać do klasy pomocniczej:

public static boolean isAppInForeground(Context context) {
  List<RunningTaskInfo> task =
      ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE))
          .getRunningTasks(1);
  if (task.isEmpty()) {
    return false;
  }
  return task
      .get(0)
      .topActivity
      .getPackageName()
      .equalsIgnoreCase(context.getPackageName());
}

Jak wspomniano w innych odpowiedziach, musisz dodać następujące uprawnienia do swojego AndroidManifest.xml.

<uses-permission android:name="android.permission.GET_TASKS"/>
Pierre-Antoine
źródło
W systemie Android Lollipop to uprawnienie jest przestarzałe
Mussa
1

Chciałbym dodać, że bezpieczniejszym sposobem na zrobienie tego - niż sprawdzanie, czy Twoja aplikacja działa w tle przed utworzeniem powiadomienia - jest po prostu wyłączenie i włączenie odbiornika transmisji onPause () i onResume ().

Ta metoda zapewnia większą kontrolę nad rzeczywistą logiką aplikacji i prawdopodobnie nie ulegnie zmianie w przyszłości.

@Override
protected void onPause() {
    unregisterReceiver(mHandleMessageReceiver);
    super.onPause();
}

@Override
protected void onResume() {
    super.onResume();
    registerReceiver(mHandleMessageReceiver, new IntentFilter(DISPLAY_MESSAGE_ACTION));
}
d4c0d312
źródło
1

Znalazłem prostszy i dokładniejszy sposób sprawdzenia, czy aplikacja działa na pierwszym planie, czy w tle, mapując działania na wartości logiczne.

Sprawdź całą treść tutaj

mipreamble
źródło
1

Oto kod ładnego prostego rozwiązania opisanego powyżej przez @ user2690455. Chociaż wygląda trochę rozwlekle, zobaczysz, że ogólnie jest dość lekki

W moim przypadku używamy również AppCompatActivity, więc musiałem mieć 2 klasy bazowe.

public class BaseActivity extends Activity {

    /**
     * Let field be set only in base class
     * All callers must use accessors,
     * and then it's not up to them to manage state.
     *
     * Making it static since ..
     * 1. It needs to be used across two base classes
     * 2. It's a singleton state in the app
     */
    private static boolean IS_APP_IN_BACKGROUND = false;

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

        BaseActivity.onResumeAppTracking(this);

        BaseActivity.setAppInBackgroundFalse();
    }

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

        BaseActivity.setAppInBackgroundTrue();
    }

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

        BaseActivity.setAppInBackgroundFalse();
    }

    protected static void onResumeAppTracking(Activity activity) {

        if (BaseActivity.isAppInBackground()) {

            // do requirements for returning app to foreground
        }

    }

    protected static void setAppInBackgroundFalse() {

        IS_APP_IN_BACKGROUND = false;
    }

    protected static void setAppInBackgroundTrue() {

        IS_APP_IN_BACKGROUND = true;
    }

    protected static boolean isAppInBackground() {

        return IS_APP_IN_BACKGROUND;
    }
}
Gene Bo
źródło
1

Jest to przydatne tylko wtedy, gdy chcesz wykonać jakąś czynność tuż po rozpoczęciu działania i tam, gdzie chcesz sprawdzić, czy aplikacja jest na pierwszym planie, czy w tle.

Zamiast korzystać z Menedżera aktywności, istnieje prosta sztuczka, którą można wykonać za pomocą kodu. Jeśli uważnie obserwujesz cykl aktywności, przepływ między dwoma działaniami i pierwszym planem w tle jest następujący. Załóżmy, że A i B to dwie czynności.

Kiedy następuje przejście z A do B: 1. wywoływana jest funkcja onPause () z A 2. Wywoływana jest metoda onResume () z B 3. Wywoływana jest funkcja onStop () z A, gdy B jest w pełni wznowiona

Kiedy aplikacja przechodzi w tło: 1. wywoływana jest funkcja onPause () z A 2. Wywoływana jest metoda onStop () z A.

Możesz wykryć zdarzenie w tle, po prostu umieszczając flagę w działaniu.

Utwórz abstrakcyjne działanie i rozszerz je na inne, tak aby nie trzeba było kopiować i wklejać kodu dla wszystkich innych działań, gdziekolwiek potrzebujesz zdarzenia w tle.

W aktywności abstrakcyjnej utwórz flagę isAppInBackground.

W metodzie onCreate (): isAppInBackground = false;

W metodzie onPause (): isAppInBackground = false;

W metodzie onStop (): isAppInBackground = true;

Musisz tylko sprawdzić w swojej onResume (), czy isAppInBackground jest prawdziwe. n po sprawdzeniu flagi ustaw ponownie isAppInBackground = false

Dla przejścia między dwoma działaniami, ponieważ onSTop () of first będzie zawsze wywoływany po wznowieniu drugiego działania, flag nigdy nie będzie true, a gdy aplikacja jest w tle, onStop () aktywności zostanie wywołana natychmiast po onPause i dlatego flaga będzie miała wartość true, gdy otworzysz aplikację później.

W tym podejściu jest jeszcze jeden scenariusz. Jeśli którykolwiek z ekranów aplikacji jest już otwarty, a telefon komórkowy zostanie przełączony w stan bezczynności, po pewnym czasie telefon przejdzie w tryb uśpienia, a po odblokowaniu telefonu komórkowego zostanie potraktowany w tle.

Ankita
źródło
1

Oto metoda, której używam (i metoda pomocnicza):

private boolean checkIfAppIsRunningInForeground() {
    ActivityManager activityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
    for(ActivityManager.RunningAppProcessInfo appProcessInfo : activityManager.getRunningAppProcesses()) {
        if(appProcessInfo.processName.contains(this.getPackageName())) {
            return checkIfAppIsRunningInForegroundByAppImportance(appProcessInfo.importance);
        }
    }
    return false;
}

private boolean checkIfAppIsRunningInForegroundByAppImportance(int appImportance) {
    switch (appImportance) {
        //user is aware of app
        case ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND:
        case ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE:
            return true;
        //user is not aware of app
        case ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND:
        case ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY:
        case ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE:
        case ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE:
        default:
            return false;
    }
}
Droid Chris
źródło
wygląda na to, że padłem głosem na rozwiązanie, które zostało opublikowane dwa lata temu. Ta metoda nie działa już po różnych aktualizacjach zabezpieczeń w systemie Android.
Droid Chris
0

Nie ma do tego globalnego wywołania zwrotnego, ale dla każdego działania jest to onStop (). Nie musisz zadzierać z atomowym int. Wystarczy mieć globalną liczbę int z liczbą rozpoczętych działań, w każdym działaniu zwiększaj ją w onStart () i zmniejszaj w onStop ().

Postępuj zgodnie z tym

Kishan Vaghela
źródło
0
     public static boolean isAppRunning(Context context) {

 // check with the first task(task in the foreground)
 // in the returned list of tasks

   ActivityManager activityManager = (ActivityManager)
   context.getSystemService(Context.ACTIVITY_SERVICE);
 List<RunningTaskInfo> services =
 activityManager.getRunningTasks(Integer.MAX_VALUE);
     if
     (services.get(0).topActivity.getPackageName().toString().equalsIgnoreCase(context.getPackageName().toString()))
     {
     return true;
     }
     return false;
     }
Ashish Soni
źródło
getRunningTasks nie jest już opcją - nowszy model zabezpieczeń sprawia, że ​​jest to w większości bezużyteczne i jest przestarzałe.
Tony Maro
@AnaghHegde Zobacz powyższą odpowiedź autorstwa Gadenkan, wyciągając listę uruchomionych działań z systemu.
Tony Maro,
0

Wspomniane wcześniej podejścia nie są optymalne. Podejście oparte na zadaniach wymaga pozwolenia, które może nie być pożądane, a podejście „logiczne” jest podatne na jednoczesne błędy związane z modyfikacjami.

Podejście, które stosuję i które (moim zdaniem) działa całkiem dobrze w większości przypadków:

Miej klasę „MainApplication”, aby śledzić liczbę działań w AtomicInteger :

import android.app.Application;

import java.util.concurrent.atomic.AtomicInteger;

public class MainApplication extends Application {
    static class ActivityCounter {
        private static AtomicInteger ACTIVITY_COUNT = new AtomicInteger(0);

        public static boolean isAppActive() {
            return ACTIVITY_COUNT.get() > 0;
        }

        public static void activityStarted() {
            ACTIVITY_COUNT.incrementAndGet();
        }

        public static void activityStopped() {
            ACTIVITY_COUNT.decrementAndGet();
        }
    }
}

I utwórz podstawową klasę Activity, którą rozszerzyłyby inne działania:

import android.app.Activity;
import android.support.annotation.CallSuper;

public class TestActivity extends Activity {
    @Override
    @CallSuper
    protected void onStart() {
        MainApplication.ActivityCounter.activityStarted();
        super.onStart();
    }

    @Override
    @CallSuper
    protected void onStop() {
        MainApplication.ActivityCounter.activityStopped();
        super.onStop();
    }
}
Tadas Šubonis
źródło
OK ... ale rozważ użycie ACTIVITY_COUNT.decrementAndGet (); w activityStopped ().
ChrisCarneiro