So erkennen Sie, wenn eine Android-App in den Hintergrund geht und wieder in den Vordergrund kommt

Lesezeit: 8 Minuten

So erkennen Sie wenn eine Android App in den Hintergrund geht
iPferd

Ich versuche, eine App zu schreiben, die etwas Bestimmtes tut, wenn sie nach einiger Zeit wieder in den Vordergrund geholt wird. Gibt es eine Möglichkeit zu erkennen, wann eine App in den Hintergrund gesendet oder in den Vordergrund gebracht wird?

  • Möglicherweise soll der Frage ein Anwendungsfall hinzugefügt werden, da dies nicht offensichtlich zu sein scheint und daher in den gegebenen Antworten nicht angesprochen wird. Die App startet möglicherweise eine andere App (z. B. Galerie), die sich weiterhin im selben Stapel befindet und als einer der Bildschirme der App angezeigt wird, und drückt dann die Home-Taste. Keine der Methoden, die sich auf den App-Lebenszyklus (oder sogar die Speicherverwaltung) verlassen, kann dies erkennen. Sie würden den Hintergrundstatus direkt auslösen, wenn eine externe Aktivität angezeigt wird, nicht wenn Sie Home drücken.

    – Dennis K

    25. März 2015 um 19:41 Uhr

  • Dies ist die gesuchte Antwort: stackoverflow.com/a/42679191/2352699

    – Fred Porciúncula

    8. März 2017 um 18:42 Uhr

  • Siehe Google-Lösung: stackoverflow.com/questions/3667022/…

    – StepanM

    13. Februar 2018 um 13:17 Uhr

Hier ist, wie ich es geschafft habe, dies zu lösen. Es funktioniert auf der Prämisse, dass die Verwendung einer Zeitreferenz zwischen Aktivitätsübergängen höchstwahrscheinlich einen angemessenen Beweis dafür liefert, ob eine App “im Hintergrund” war oder nicht.

Zuerst habe ich eine android.app.Application-Instanz (nennen wir sie MyApplication) verwendet, die einen Timer, eine TimerTask, eine Konstante hat, die die maximale Anzahl von Millisekunden darstellt, die der Übergang von einer Aktivität zu einer anderen vernünftigerweise dauern könnte (ich ging mit einem Wert von 2s) und einen booleschen Wert, um anzugeben, ob die App “im Hintergrund” war oder nicht:

public class MyApplication extends Application {

    private Timer mActivityTransitionTimer;
    private TimerTask mActivityTransitionTimerTask;
    public boolean wasInBackground;
    private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;
    ...

Die Anwendung bietet außerdem zwei Methoden zum Starten und Stoppen des Timers/der Aufgabe:

public void startActivityTransitionTimer() {
    this.mActivityTransitionTimer = new Timer();
    this.mActivityTransitionTimerTask = new TimerTask() {
        public void run() {
            MyApplication.this.wasInBackground = true;
        }
    };

    this.mActivityTransitionTimer.schedule(mActivityTransitionTimerTask,
                                           MAX_ACTIVITY_TRANSITION_TIME_MS);
}

public void stopActivityTransitionTimer() {
    if (this.mActivityTransitionTimerTask != null) {
        this.mActivityTransitionTimerTask.cancel();
    }

    if (this.mActivityTransitionTimer != null) {
        this.mActivityTransitionTimer.cancel();
    }

    this.wasInBackground = false;
}

Der letzte Teil dieser Lösung besteht darin, jeder dieser Methoden einen Aufruf aus den onResume()- und onPause()-Ereignissen aller Aktivitäten oder vorzugsweise in einer Basisaktivität hinzuzufügen, von der alle Ihre konkreten Aktivitäten erben:

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

    MyApplication myApp = (MyApplication)this.getApplication();
    if (myApp.wasInBackground)
    {
        //Do specific came-here-from-background code
    }

    myApp.stopActivityTransitionTimer();
}

@Override
public void onPause()
{
    super.onPause();
    ((MyApplication)this.getApplication()).startActivityTransitionTimer();
}

Wenn der Benutzer also einfach zwischen den Aktivitäten Ihrer App navigiert, startet onPause() der abgehenden Aktivität den Timer, aber fast sofort bricht die neue Aktivität, die eingegeben wird, den Timer ab, bevor sie die maximale Übergangszeit erreichen kann. Und so warImHintergrund wäre falsch.

Wenn andererseits eine Aktivität vom Launcher in den Vordergrund kommt, das Gerät aufwacht, den Anruf beendet usw., wird höchstwahrscheinlich die Timer-Aufgabe vor diesem Ereignis ausgeführt, und somit warImHintergrund eingestellt war wahr.

  • Hallo d60402, Ihre Antwort ist wirklich hilfreich. Vielen Dank für diese Antwort … kleiner Hinweis. MyApplication sollte in der Manifestdatei das Anwendungs-Tag wie android:name=”MyApplication” erwähnen, andernfalls stürzt die App ab … nur um zu helfen jemand wie ich

    – praveenb

    1. August 2013 um 6:04 Uhr

  • Zeichen des großen Programmierers, einfache Lösung für eines der kompliziertesten Probleme, auf die ich je gestoßen bin.

    – Aashish Bhatnagar

    4. Januar 2014 um 16:53 Uhr

  • Tolle Lösung! Danke. Wenn jemand den „ClassCastException“-Fehler erhält, haben Sie es möglicherweise verpasst, ihn im Anwendungs-Tag in Ihrer Manifest.xml

    – Wahib Ul Haq

    23. Januar 2014 um 21:56 Uhr


  • Dies ist eine schöne und einfache Implementierung. Ich glaube jedoch, dass dies in onStart/onStop und nicht in onPause/onResume implementiert werden sollte. Die onPause wird auch dann aufgerufen, wenn ich einen Dialog starte, der die Aktivität teilweise abdeckt. Und das Schließen des Dialogs würde tatsächlich onResume aufrufen, sodass es so aussieht, als wäre die App gerade in den Vordergrund gekommen

    – Shubhayu

    25. März 2014 um 17:16 Uhr

  • Ich hoffe, eine Variation dieser Lösung zu verwenden. Der oben identifizierte Punkt zu Dialogen ist ein Problem für mich, daher habe ich den Vorschlag von @Shubhayu (onStart/onStop) ausprobiert. Das hilft jedoch nicht, da beim Wechseln von A-> B onStart() von Activity B vor onStop() von Activity A aufgerufen wird.

    – Trevor

    14. August 2014 um 14:12 Uhr

  • Das funktioniert perfekt! Ich habe schon so viele seltsame Lösungen ausprobiert, die so viele Fehler hatten … vielen Dank! Ich suche das schon eine Weile.

    – Eggakin Baconwalker

    23. März 2017 um 12:04 Uhr

  • Es funktioniert für mehrere Aktivitäten, aber für eine – onrotate zeigt an, ob alle Aktivitäten weg oder im Hintergrund sind

    – toter Fisch

    20. Mai 2017 um 18:16 Uhr

  • @Shyri du hast Recht, aber das ist Teil dieser Lösung, also musst du dir Sorgen machen. Wenn sich Firebase darauf verlässt, kann das meiner Meinung nach auch meine mittelmäßige App 🙂 Tolle Antwort Übrigens.

    – ElliotM

    1. August 2017 um 20:45 Uhr


  • @deadfish Überprüfen Sie den Link zu I/O oben in der Antwort. Sie können Zeitlücken zwischen Aktivitätsstopp und -start überprüfen, um festzustellen, ob Sie wirklich in den Hintergrund gegangen sind oder nicht. Das ist eigentlich eine geniale Lösung.

    – Alex Berdnikow

    29. August 2017 um 17:25 Uhr

  • Gibt es eine Java-Lösung? Das ist Kotlin.

    – Giacomo Bartoli

    22. Januar 2018 um 20:55 Uhr

So erkennen Sie wenn eine Android App in den Hintergrund geht
Vokilam

Update November 2021

Die tatsächliche Einrichtung ist wie folgt

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleListener())
    }
}

class AppLifecycleListener : DefaultLifecycleObserver {

    override fun onStart(owner: LifecycleOwner) { // app moved to foreground
    }

    override fun onStop(owner: LifecycleOwner) { // app moved to background
    }
}

Abhängigkeiten

implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common:$lifecycle_version"

ORIGINALE ANTWORT

ProcessLifecycleOwner scheint auch eine vielversprechende Lösung zu sein.

ProcessLifecycleOwner versendet ON_START, ON_RESUME Ereignisse, da sich eine erste Aktivität durch diese Ereignisse bewegt. ON_PAUSE, ON_STOPEreignisse werden mit a versendet verzögern nachdem eine letzte Aktivität durch sie gegangen ist. Diese Verzögerung ist lang genug, um dies zu gewährleisten ProcessLifecycleOwner sendet keine Ereignisse, wenn Aktivitäten aufgrund einer Konfigurationsänderung zerstört und neu erstellt werden.

Eine Implementierung kann so einfach sein wie

class AppLifecycleListener : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onMoveToForeground() { // app moved to foreground
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onMoveToBackground() { // app moved to background
    }
}

// register observer
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleListener())

Entsprechend Quellcodeaktueller Verzögerungswert ist 700ms.

Auch die Verwendung dieser Funktion erfordert die dependencies:

implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"

  • Beachten Sie, dass Sie die Lebenszyklusabhängigkeiten hinzufügen müssen implementation "android.arch.lifecycle:extensions:1.0.0" und annotationProcessor "android.arch.lifecycle:compiler:1.0.0" aus dem Repository von Google (dh google())

    – Herr Codesalot

    24. Dezember 2017 um 12:03 Uhr


  • Das hat bei mir super funktioniert, danke. Ich musste die API ‘android.arch.lifecycle:extensions:1.1.0’ anstelle der Implementierung verwenden, da der Fehler besagt, dass die Android-Abhängigkeit eine andere Version für den Klassenpfad für die Kompilierung und die Laufzeit hat.

    – FSUWX2011

    9. März 2018 um 20:00 Uhr

  • Dies ist eine großartige Lösung, da sie in Modulen funktioniert, ohne dass eine Aktivitätsreferenz erforderlich ist!

    – max

    23. April 2018 um 23:15 Uhr

  • Dies funktioniert nicht, wenn die App abgestürzt ist. Gibt es eine Lösung, um das App-Absturzereignis auch über diese Lösung zu erhalten

    – tejraj

    15. Mai 2019 um 12:31 Uhr

  • @SirCodesalot ist für die nicht erforderlich 2.2.0 Ausführung.

    – artem

    24. Juli 2020 um 18:36 Uhr

Die onPause() und onResume() Methoden werden aufgerufen, wenn die Anwendung in den Hintergrund und wieder in den Vordergrund gebracht wird. Sie werden jedoch auch aufgerufen, wenn die Anwendung zum ersten Mal gestartet wird und bevor sie beendet wird. Sie können mehr in lesen Aktivität.

Es gibt keinen direkten Ansatz, um den Anwendungsstatus im Hintergrund oder Vordergrund abzurufen, aber selbst ich bin mit diesem Problem konfrontiert und habe die Lösung gefunden onWindowFocusChanged und onStop.

Weitere Informationen finden Sie hier Android: Lösung zum Erkennen, wenn eine Android-App in den Hintergrund wechselt und ohne getRunningTasks oder getRunningAppProcesses wieder in den Vordergrund kommt.

  • Beachten Sie, dass Sie die Lebenszyklusabhängigkeiten hinzufügen müssen implementation "android.arch.lifecycle:extensions:1.0.0" und annotationProcessor "android.arch.lifecycle:compiler:1.0.0" aus dem Repository von Google (dh google())

    – Herr Codesalot

    24. Dezember 2017 um 12:03 Uhr


  • Das hat bei mir super funktioniert, danke. Ich musste die API ‘android.arch.lifecycle:extensions:1.1.0’ anstelle der Implementierung verwenden, da der Fehler besagt, dass die Android-Abhängigkeit eine andere Version für den Klassenpfad für die Kompilierung und die Laufzeit hat.

    – FSUWX2011

    9. März 2018 um 20:00 Uhr

  • Dies ist eine großartige Lösung, da sie in Modulen funktioniert, ohne dass eine Aktivitätsreferenz erforderlich ist!

    – max

    23. April 2018 um 23:15 Uhr

  • Dies funktioniert nicht, wenn die App abgestürzt ist. Gibt es eine Lösung, um das App-Absturzereignis auch über diese Lösung zu erhalten

    – tejraj

    15. Mai 2019 um 12:31 Uhr

  • @SirCodesalot ist für die nicht erforderlich 2.2.0 Ausführung.

    – artem

    24. Juli 2020 um 18:36 Uhr

Basierend auf Martín Marconcinis Antwort (danke!) habe ich endlich eine zuverlässige (und sehr einfache) Lösung gefunden.

public class ApplicationLifecycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {

    private static final String TAG = ApplicationLifecycleHandler.class.getSimpleName();
    private static boolean isInBackground = false;

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

    @Override
    public void onActivityStarted(Activity activity) {
    }

    @Override
    public void onActivityResumed(Activity activity) {

        if(isInBackground){
            Log.d(TAG, "app went to foreground");
            isInBackground = false;
        }
    }

    @Override
    public void onActivityPaused(Activity activity) {
    }

    @Override
    public void onActivityStopped(Activity activity) {
    }

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

    @Override
    public void onActivityDestroyed(Activity activity) {
    }

    @Override
    public void onConfigurationChanged(Configuration configuration) {
    }

    @Override
    public void onLowMemory() {
    }

    @Override
    public void onTrimMemory(int i) {
        if(i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){
            Log.d(TAG, "app went to background");
            isInBackground = true;
        }
    }
}

Fügen Sie dies dann zu Ihrem onCreate() Ihrer Anwendungsklasse hinzu

public class MyApp extends android.app.Application {

    @Override
    public void onCreate() {
        super.onCreate();

        ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
        registerActivityLifecycleCallbacks(handler);
        registerComponentCallbacks(handler);

    }

}

  • Können Sie zeigen, wie Sie dies in einer App verwenden, nenne ich das aus der App-Klasse oder woanders?

    – JPM

    31. Juli 2015 um 21:38 Uhr


  • das ist perfekt danke!! Funktioniert bisher im Test super

    – Aherrick

    18. August 2015 um 14:30 Uhr

  • Dieses Beispiel ist unvollständig. Was ist registerActivityLifecycleCallbacks?

    – Kein Mann

    7. September 2015 um 10:48 Uhr

  • Gut gemacht +1, um an die Spitze zu gehen, weil es perfekt ist, schauen Sie nicht auf andere Antworten, dies basiert auf der @reno-Antwort, aber mit echtem Beispiel

    – Stoycho Andreev

    29. Januar 2016 um 17:50 Uhr

  • Ich habe Ihre Antwort versucht, ist aber nicht so zuverlässig. Der onTrimMemory-Callback wird weder ausgelöst, wenn der Bildschirm gesperrt ist, noch wenn der „Power“-Knopf gedrückt wird, um den Bildschirm zu sperren. Es wird auch nicht immer TRIM_MEMORY_UI_HIDDEN zurückgegeben, wenn Ihre App sichtbar ist und Sie eine andere App über eine Statusleistenbenachrichtigung öffnen. Die einzige zuverlässige Lösung besteht darin, die ActivityLifecycleCallbacks zu implementieren und an den eigenen Anwendungsfall anzupassen.

    – Velval

    6. November 2016 um 11:15 Uhr


1002170cookie-checkSo erkennen Sie, wenn eine Android-App in den Hintergrund geht und wieder in den Vordergrund kommt

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy