380 Stimmen

Prüfen, ob eine Android-Anwendung im Hintergrund läuft

Mit Hintergrund meine ich, dass keine der Aktivitäten der Anwendung derzeit für den Benutzer sichtbar sind?

11voto

Ich habe die empfohlene Lösung ausprobiert, bei der Application.ActivityLifecycleCallbacks und viele andere, aber sie haben nicht wie erwartet funktioniert. Dank an Sarge Ich habe eine ziemlich einfache und unkomplizierte Lösung gefunden, die ich im Folgenden beschreibe.

Der Schlüssel zur Lösung ist die Tatsache, dass wir verstehen, dass, wenn wir ActivityA und ActivityB haben und ActivityB von ActivityA aus aufrufen (und nicht ActivityA.finish ), dann ist ActivityB's onStart() wird aufgerufen vor TätigkeitA onStop() .

Das ist auch die Haupt Unterschied zwischen onStop() y onPause() die in den Artikeln, die ich gelesen habe, nicht erwähnt wurden.

Auf der Grundlage des Lebenszyklusverhaltens dieser Aktivität können Sie also einfach zählen, wie oft die onStart() y onPause() in Ihrem Programm aufgerufen wurde. Beachten Sie, dass für jede Activity Ihres Programms, müssen Sie die onStart() y onStop() um die für die Zählung verwendete statische Variable zu erhöhen/verringern. Im Folgenden finden Sie den Code, der diese Logik implementiert. Beachten Sie, dass ich eine Klasse verwende, die die Application also vergessen Sie nicht, sich anzumelden Manifest.xml innerhalb des Anwendungstags: android:name=".Utilities" obwohl sie auch mit einer einfachen benutzerdefinierten Klasse implementiert werden kann.

public class Utilities extends Application
{
    private static int stateCounter;

    public void onCreate()
    {
        super.onCreate();
        stateCounter = 0;
    }

    /**
     * @return true if application is on background
     * */
    public static boolean isApplicationOnBackground()
    {
        return stateCounter == 0;
    }

    //to be called on each Activity onStart()
    public static void activityStarted()
    {
        stateCounter++;
    }

    //to be called on each Activity onStop()
    public static void activityStopped()
    {
        stateCounter--;
    }
}

Jetzt sollten wir in jeder Aktivität unseres Programms die folgenden Befehle überschreiben onStart() y onStop() und erhöhen/verringern wie unten dargestellt:

@Override
public void onStart()
{
    super.onStart();
    Utilities.activityStarted();
}

@Override
public void onStop()
{
    Utilities.activityStopped();
    if(Utilities.isApplicationOnBackground())
    {
        //you should want to check here if your application is on background
    }
    super.onStop();
}

Nach dieser Logik gibt es 2 mögliche Fälle:

  1. stateCounter = 0 : Die Anzahl der gestoppten ist gleich der Anzahl der gestarteten Aktivitäten, was bedeutet, dass die Anwendung im Hintergrund läuft.
  2. stateCounter > 0 : Die Anzahl der gestarteten ist größer als die Anzahl der gestoppten, was bedeutet, dass die Anwendung im Vordergrund läuft.

Hinweis: stateCounter < 0 würde bedeuten, dass es mehr eingestellte als begonnene Aktivitäten gibt, was unmöglich ist. Wenn dieser Fall eintritt, bedeutet dies, dass Sie den Zähler nicht wie vorgesehen erhöhen/verringern.

Sie sind bereit zum Aufbruch. Sie sollten prüfen wollen, ob Ihre Anwendung im Hintergrund läuft onStop() .

10voto

CommonsWare Punkte 950864

Es gibt keine Möglichkeit, festzustellen, ob eine Ihrer Aktivitäten sichtbar ist oder nicht, es sei denn, Sie verfolgen sie selbst. Vielleicht sollten Sie in Erwägung ziehen, eine neue StackOverflow-Frage zu stellen, in der Sie erklären, was Sie in Bezug auf die Benutzererfahrung erreichen möchten, damit wir Ihnen vielleicht alternative Implementierungsideen geben können.

5voto

Rohit Arya Punkte 6643

Sie können verwenden KomponenteCallbacks2 um zu erkennen, ob die Anwendung im Hintergrund läuft. Übrigens ist dieser Callback nur verfügbar in API Level 14 (Ice Cream Sandwich) und höher.

Sie erhalten einen Aufruf der Methode:

public abstract void onTrimMemory (int level)

wenn der Pegel ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN dann ist die App im Hintergrund.

Sie können diese Schnittstelle in eine activity , service , usw.

public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
   @Override
   public void onConfigurationChanged(final Configuration newConfig) {

   }

   @Override
   public void onLowMemory() {

   }

   @Override
   public void onTrimMemory(final int level) {
     if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
        // app is in background
     }
   }
}

4voto

seb Punkte 389

Aufbauend auf @Cornstalks Antwort, um einige nützliche Funktionen einzubeziehen.

Zusätzliche Merkmale:

  • Singleton-Muster eingeführt, so dass Sie dies überall in der Anwendung tun können: AppLifecycleHandler.isApplicationVisible() und AppLifecycleHandler.isApplicationInForeground()
  • Behandlung von doppelten Ereignissen hinzugefügt (siehe Kommentare // Aktion bei Änderung der Sichtbarkeit und // Aktion bei Änderung des Vordergrunds)

App.java

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance());
    }
}

AppLifecycleHandler.java

public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
    private int resumed;
    private int started;

    private final String DebugName = "AppLifecycleHandler";

    private boolean isVisible = false;
    private boolean isInForeground = false;

    private static AppLifecycleHandler instance;

    public static AppLifecycleHandler getInstance() {
        if (instance == null) {
            instance = new AppLifecycleHandler();
        }

        return instance;
    }

    private AppLifecycleHandler() {
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
    }

    @Override
    public void onActivityResumed(Activity activity) {
        ++resumed;
        android.util.Log.w(DebugName, "onActivityResumed -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
        setForeground((resumed > 0));
    }

    @Override
    public void onActivityPaused(Activity activity) {
        --resumed;
        android.util.Log.w(DebugName, "onActivityPaused -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
        setForeground((resumed > 0));
    }

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

    @Override
    public void onActivityStarted(Activity activity) {
        ++started;
        android.util.Log.w(DebugName, "onActivityStarted -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
        setVisible((started > 0));
    }

    @Override
    public void onActivityStopped(Activity activity) {
        --started;
        android.util.Log.w(DebugName, "onActivityStopped -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
        setVisible((started > 0));
    }

    private void setVisible(boolean visible) {
        if (isVisible == visible) {
            // no change
            return;
        }

        // visibility changed
        isVisible = visible;
        android.util.Log.w(DebugName, "App Visiblility Changed -> application is visible: " + isVisible);

        // take some action on change of visibility
    }

    private void setForeground(boolean inForeground) {
        if (isInForeground == inForeground) {
            // no change
            return;
        }

        // in foreground changed
        isInForeground = inForeground;
        android.util.Log.w(DebugName, "App In Foreground Changed -> application is in foreground: " + isInForeground);

        // take some action on change of in foreground

    }

    public static boolean isApplicationVisible() {
        return AppLifecycleHandler.getInstance().started > 0;
    }

    public static boolean isApplicationInForeground() {
        return AppLifecycleHandler.getInstance().resumed > 0;
    }
}

3voto

Andrew Kelly Punkte 2120

Die beste Lösung, die ich gefunden habe, sind Zeitschaltuhren.

Sie haben einen Timer in onPause() gestartet und denselben Timer in onResume() abgebrochen, es gibt 1 Instanz des Timers (normalerweise in der Klasse Application definiert). Der Timer selbst ist so eingestellt, dass er nach 2 Sekunden (oder in einem anderen Intervall, das Sie für angemessen halten) eine Runnable ausführt; wenn der Timer ausgelöst wird, setzen Sie ein Flag, das die Anwendung als im Hintergrund befindlich kennzeichnet.

In der onResume()-Methode können Sie, bevor Sie den Timer abbrechen, das Hintergrundflag abfragen, um etwaige Startvorgänge durchzuführen (z. B. Downloads zu starten oder Standortdienste zu aktivieren).

Diese Lösung ermöglicht es Ihnen, mehrere Aktivitäten auf dem Backstack zu haben, und erfordert keine Berechtigungen zur Implementierung.

Diese Lösung funktioniert auch gut, wenn Sie einen Ereignisbus verwenden, da Ihr Timer einfach ein Ereignis auslösen kann und verschiedene Teile Ihrer Anwendung entsprechend reagieren können.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X