Mit Hintergrund meine ich, dass keine der Aktivitäten der Anwendung derzeit für den Benutzer sichtbar sind?
Antworten
Zu viele Anzeigen?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'sonStart()
wird aufgerufen vor TätigkeitAonStop()
.
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:
stateCounter = 0
: Die Anzahl der gestoppten ist gleich der Anzahl der gestarteten Aktivitäten, was bedeutet, dass die Anwendung im Hintergrund läuft.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()
.
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.
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
}
}
}
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;
}
}
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.