Mit Hintergrund meine ich, dass keine der Aktivitäten der Anwendung derzeit für den Benutzer sichtbar sind?
Antworten
Zu viele Anzeigen?Es gibt nur wenige Möglichkeiten zu erkennen, ob Ihre Anwendung im Hintergrund läuft, aber nur eine davon ist absolut zuverlässig:
-
Die richtige Lösung (Credits gehen an Dan , CommonsWare y NeTeInStEiN )
Verfolgen Sie die Sichtbarkeit Ihrer Bewerbung selbst mitActivity.onPause
,Activity.onResume
Methoden. Speichern Sie den Status "Sichtbarkeit" in einer anderen Klasse. Eine gute Wahl ist Ihre eigene Implementierung derApplication
oder eineService
(es gibt auch ein paar Variationen dieser Lösung, wenn Sie die Sichtbarkeit der Aktivitäten des Dienstes überprüfen möchten).
Beispiel
Benutzerdefiniert implementierenApplication
Klasse (beachten Sie dieisActivityVisible()
statische Methode):public class MyApplication extends Application { public static boolean isActivityVisible() { return activityVisible; } public static void activityResumed() { activityVisible = true; } public static void activityPaused() { activityVisible = false; } private static boolean activityVisible; }
Registrieren Sie Ihre Bewerbungsklasse in
AndroidManifest.xml
:<application android:name="your.app.package.MyApplication" android:icon="@drawable/icon" android:label="@string/app_name" >
hinzufügen
onPause
yonResume
für jedenActivity
im Projekt (Sie können einen gemeinsamen Vorgänger für Ihre Aktivitäten erstellen, wenn Sie das möchten, aber wenn Ihre Aktivität bereits vonMapActivity
/ListActivity
usw. müssen Sie die folgenden Angaben noch von Hand schreiben):@Override protected void onResume() { super.onResume(); MyApplication.activityResumed(); } @Override protected void onPause() { super.onPause(); MyApplication.activityPaused(); }
Update
ActivityLifecycleCallbacks wurden in API Stufe 14 (Android 4.0) hinzugefügt. Sie können sie verwenden, um festzustellen, ob eine Aktivität Ihrer Anwendung derzeit für den Benutzer sichtbar ist. prüfen Antwort von Cornstalks unten für die Details. -
Der Falsche
Ich habe immer die folgende Lösung vorgeschlagen:Sie können die aktuelle Vordergrund/Hintergrund-Anwendung mit
ActivityManager.getRunningAppProcesses()
die eine Liste vonRunningAppProcessInfo
Aufzeichnungen. Um festzustellen, ob Ihre Anwendung im Vordergrund steht, prüfen SieRunningAppProcessInfo.importance
Feld für Gleichheit mitRunningAppProcessInfo.IMPORTANCE_FOREGROUND
alors queRunningAppProcessInfo.processName
gleich dem Namen Ihres Anwendungspakets ist.Auch wenn Sie anrufen
ActivityManager.getRunningAppProcesses()
von Ihrem Anwendungs-UI-Thread wird es wichtig zurückgebenIMPORTANCE_FOREGROUND
für Ihre Aufgabe, unabhängig davon, ob sie tatsächlich im Vordergrund ist oder nicht. Rufen Sie sie im Hintergrund-Thread auf (zum Beispiel überAsyncTask
) und es wird korrekte Ergebnisse liefern.Diese Lösung kann zwar funktionieren (und sie funktioniert in der Tat meistens), aber ich empfehle dringend, davon abzusehen, sie zu verwenden. Und hier ist der Grund dafür. Wie Dianne Hackborn schrieb :
Diese APIs sind nicht dazu da, dass Anwendungen ihren UI-Flow darauf aufbauen, sondern dazu, dem Benutzer die laufenden Anwendungen oder einen Taskmanager oder ähnliches anzuzeigen.
Ja, es gibt eine Liste, in der diese Dinge festgehalten werden. Sie befindet sich jedoch in einem anderen Prozess, der von Threads verwaltet wird, die getrennt von Ihrem Prozess laufen, und Sie können sich nicht darauf verlassen, dass Sie (a) sie rechtzeitig sehen, um die richtige Entscheidung zu treffen, oder (b) ein konsistentes Bild haben, wenn Sie zurückkehren. Außerdem wird die Entscheidung über die "nächste" Aktivität immer an dem Punkt getroffen, an dem der Wechsel stattfinden soll, und erst an diesem exakten Punkt (an dem der Aktivitätsstatus kurzzeitig gesperrt wird, um den Wechsel vorzunehmen) wissen wir mit Sicherheit, was als Nächstes ansteht.
Und es ist nicht garantiert, dass die Umsetzung und das globale Verhalten in der Zukunft gleich bleiben werden.
Ich wünschte, ich hätte dies gelesen, bevor ich eine Antwort auf die SO gepostet habe, aber hoffentlich ist es noch nicht zu spät, meinen Fehler einzugestehen.
-
Eine weitere falsche Lösung
Droiden-Fu Die in einer der Antworten erwähnte Bibliothek verwendetActivityManager.getRunningTasks
für seineisApplicationBroughtToBackground
Methode. Siehe Diannes Kommentar oben und verwenden Sie auch diese Methode nicht.
GOOGLE-LÖSUNG - kein Hack, wie bei früheren Lösungen. Verwenden Sie ProcessLifecycleOwner
Kotlin:
class ArchLifecycleApp : Application(), LifecycleObserver {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {
// App in foreground
}
}
Java:
public class ArchLifecycleApp extends Application implements LifecycleObserver {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppForegrounded() {
// App in foreground
}
}
in app.gradle
dependencies {
...
implementation "android.arch.lifecycle:extensions:1.1.0"
//New Android X dependency is this -
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
}
allprojects {
repositories {
...
google()
jcenter()
maven { url 'https://maven.google.com' }
}
}
Hier können Sie mehr über die lebenszyklusbezogenen Architekturkomponenten lesen. https://developer.Android.com/topic/libraries/architecture/lifecycle
VERWENDEN SIE DIESE ANTWORT NICHT
Die Antwort von user1269737 ist der richtige (von Google/Android genehmigte) Weg, dies zu tun . Lesen Sie ihre Antwort und geben Sie ihnen ein +1.
Ich werde meine ursprüngliche Antwort der Nachwelt zuliebe hier lassen. Dies war die beste verfügbare zurück im Jahr 2012, aber jetzt Android hat richtige Unterstützung für diese.
Ursprüngliche Antwort
Der Schlüssel ist die Verwendung von ActivityLifecycleCallbacks
(Beachten Sie, dass dafür Android API Level 14 (Android 4.0) erforderlich ist). Prüfen Sie einfach, ob die Anzahl der gestoppten Aktivitäten gleich der Anzahl der gestarteten Aktivitäten ist. Wenn sie gleich sind, wird Ihre Anwendung im Hintergrund ausgeführt. Wenn es mehr gestartete Aktivitäten gibt, ist Ihre Anwendung noch sichtbar. Wenn es mehr wieder aufgenommene als angehaltene Aktivitäten gibt, ist Ihre Anwendung nicht nur sichtbar, sondern auch im Vordergrund. Es gibt also 3 Hauptzustände, in denen sich Ihre Aktivität befinden kann: sichtbar und im Vordergrund, sichtbar, aber nicht im Vordergrund, und nicht sichtbar und nicht im Vordergrund (d. h. im Hintergrund).
Das wirklich Schöne an dieser Methode ist, dass sie keine asynchronen Probleme hat getRunningTasks()
tut, aber Sie müssen auch nicht jede einzelne Activity
in Ihrer Anwendung, um etwas zu setzen/zu löschen in onResumed()
/ onPaused()
. Es sind nur ein paar Zeilen Code, die in sich geschlossen sind und in Ihrer gesamten Anwendung funktionieren. Außerdem sind keine komplizierten Berechtigungen erforderlich.
MyLifecycleHandler.java:
public class MyLifecycleHandler implements ActivityLifecycleCallbacks {
// I use four separate variables here. You can, of course, just use two and
// increment/decrement them instead of using four and incrementing them all.
private int resumed;
private int paused;
private int started;
private int stopped;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
}
@Override
public void onActivityPaused(Activity activity) {
++paused;
android.util.Log.w("test", "application is in foreground: " + (resumed > paused));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
}
@Override
public void onActivityStopped(Activity activity) {
++stopped;
android.util.Log.w("test", "application is visible: " + (started > stopped));
}
// If you want a static function you can use to check if your application is
// foreground/background, you can use the following:
/*
// Replace the four variables above with these four
private static int resumed;
private static int paused;
private static int started;
private static int stopped;
// And these two public static functions
public static boolean isApplicationVisible() {
return started > stopped;
}
public static boolean isApplicationInForeground() {
return resumed > paused;
}
*/
}
MyApplication.java:
// Don't forget to add it to your manifest by doing
// <application android:name="your.package.MyApplication" ...
public class MyApplication extends Application {
@Override
public void onCreate() {
// Simply add the handler, and that's it! No need to add any code
// to every activity. Everything is contained in MyLifecycleHandler
// with just a few lines of code. Now *that's* nice.
registerActivityLifecycleCallbacks(new MyLifecycleHandler());
}
}
@Mewzer hat einige gute Fragen zu dieser Methode gestellt, auf die ich in dieser Antwort für alle eingehen möchte:
onStop()
in Situationen mit wenig Speicherplatz nicht aufgerufen wird; ist das hier ein Problem?
Nein. Die Dokumentationen für onStop()
sagen:
Beachten Sie, dass diese Methode in Situationen, in denen das System nicht über genügend Speicher verfügt, um den Prozess Ihrer Aktivität nach dem Aufruf der onPause()-Methode weiterlaufen zu lassen, möglicherweise nie aufgerufen wird.
Der Schlüssel dazu ist: "Behalten Sie Ihre Aktivität bei laufender Prozess ..." Wenn dieser Zustand erreicht wird, wird Ihr Prozess tatsächlich beendet (nicht nur Ihre Aktivität). Das bedeutet, dass diese Methode der Überprüfung auf Hintergrundaktivität immer noch gültig ist, weil a) Sie sowieso nicht auf Hintergrundaktivität überprüfen können, wenn Ihr Prozess beendet wird, und b) wenn Ihr Prozess wieder startet (weil eine neue Aktivität erstellt wird), die Mitgliedsvariablen (ob statisch oder nicht) für MyLifecycleHandler
wird zurückgesetzt auf 0
.
Funktioniert das auch bei Konfigurationsänderungen?
Standardmäßig, nein. Sie müssen explizit festlegen configChanges=orientation|screensize
( |
mit allem anderen, was Sie wollen) in Ihre Manifestdatei einfügen und die Konfigurationsänderungen verarbeiten, sonst wird Ihre Aktivität zerstört und neu erstellt. Wenn Sie dies nicht festlegen, werden die Methoden Ihrer Aktivität in dieser Reihenfolge aufgerufen: onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
. Wie Sie sehen, gibt es keine Überschneidungen (normalerweise überschneiden sich zwei Aktivitäten nur sehr kurz, wenn man zwischen ihnen wechselt, und so funktioniert diese Methode zur Erkennung von Hintergrundaktivitäten). Um dies zu umgehen, müssen Sie configChanges
damit Ihre Tätigkeit nicht zerstört wird. Zum Glück musste ich die configChanges
bereits in allen meinen Projekten, weil es unerwünscht war, dass meine gesamte Aktivität beim Drehen/Ändern der Größe des Bildschirms zerstört wird, daher habe ich dies nie als problematisch empfunden. (Dank an dpimka für die Auffrischung meines Gedächtnisses und die Richtigstellung!)
Eine Anmerkung:
Wenn ich hier in dieser Antwort von "Hintergrund" gesprochen habe, meinte ich "Ihre App ist nicht mehr sichtbar". Android-Aktivitäten können sichtbar sein, ohne im Vordergrund zu sein (z. B. wenn ein transparentes Benachrichtigungs-Overlay vorhanden ist). Deshalb habe ich diese Antwort aktualisiert, um dies zu berücksichtigen.
Es ist wichtig zu wissen, dass es bei Android einen seltsamen Schwebezustand gibt, wenn man die Aktivitäten wechselt. nichts im Vordergrund steht . Wenn Sie daher beim Wechsel zwischen Aktivitäten (in derselben Anwendung) prüfen, ob sich Ihre Anwendung im Vordergrund befindet, wird Ihnen mitgeteilt, dass Sie sich nicht im Vordergrund befinden (obwohl Ihre Anwendung immer noch die aktive Anwendung ist und sichtbar ist).
Sie können überprüfen, ob sich Ihre Anwendung im Vordergrund befindet, indem Sie in Ihrer Activity
's onPause()
Methode après super.onPause()
. Erinnern Sie sich einfach an den seltsamen Schwebezustand, von dem ich gerade sprach.
Sie können überprüfen, ob Ihre Anwendung sichtbar ist (d. h. ob sie sich nicht im Hintergrund befindet) in Ihrer Activity
's onStop()
Methode après super.onStop()
.
Seit Android API 16 gibt es eine einfache Möglichkeit zu prüfen, ob die App im Vordergrund ist. Es mag nicht narrensicher sein, aber keine Methode auf Android ist narrensicher. Diese Methode ist gut genug, um zu verwenden, wenn Ihr Dienst eine Aktualisierung vom Server erhält und entscheiden muss, ob eine Benachrichtigung angezeigt werden soll oder nicht (denn wenn die Benutzeroberfläche im Vordergrund ist, wird der Benutzer die Aktualisierung ohne Benachrichtigung bemerken).
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
Die Antwort von Idolon ist fehleranfällig und viel komplizierter, auch wenn sie hier wiederholt wird prüfen, ob die Android-Anwendung im Vordergrund ist oder nicht? und hier Ermittlung der aktuellen Vordergrundanwendung aus einer Hintergrundaufgabe oder einem Dienst
Es gibt einen viel einfacheren Ansatz:
Bei einem BaseActivity, die alle Activities erweitern:
protected static boolean isVisible = false;
@Override
public void onResume()
{
super.onResume();
setVisible(true);
}
@Override
public void onPause()
{
super.onPause();
setVisible(false);
}
Wann immer Sie etwas überprüfen müssen Wenn eine Ihrer Anwendungsaktivitäten im Vordergrund ist, prüfen Sie einfach isVisible()
;
Um diesen Ansatz zu verstehen, sehen Sie sich diese Antwort zum Lebenszyklus von Side-by-Side-Aktivitäten an: Lebenszyklus von Aktivitäten nebeneinander
- See previous answers
- Weitere Antworten anzeigen