it-swarm.com.de

Singletons vs. Anwendungskontext in Android?

Ich erinnere mich an diesen Beitrag, in dem einige Probleme bei der Verwendung von Singletons aufgezählt und einige Beispiele für Android -Anwendungen mit Singleton-Muster gesehen wurden Es empfiehlt sich, Singletons anstelle einzelner Instanzen zu verwenden, die über den globalen Anwendungsstatus gemeinsam genutzt werden (Unterklassen von Android.os.Application und Abrufen über context.getApplication ()).

Welche Vor-/Nachteile hätten beide Mechanismen?

Um ehrlich zu sein, erwarte ich die gleiche Antwort in diesem Beitrag Singleton-Muster mit Webanwendung, keine gute Idee! aber auf Android angewendet. Hab ich recht? Was ist anders in DalvikVM?

EDIT: Ich hätte gerne Meinungen zu verschiedenen Aspekten:

  • Synchronisation
  • Wiederverwendbarkeit
  • Testen
360
mschonaker

Ich bin mit der Antwort von Dianne Hackborn nicht einverstanden. Wir entfernen nach und nach alle Singletons aus unserem Projekt, und zwar zugunsten von leichten Objekten mit Aufgabenbereich, die einfach neu erstellt werden können, wenn Sie sie tatsächlich benötigen.

Singletons sind ein Albtraum zum Testen und werden, wenn sie faul initialisiert werden, "Zustandsindeterminismus" mit subtilen Nebenwirkungen einführen (die plötzlich auftauchen können, wenn Aufrufe an getInstance() von einem abgehen Umfang zu einem anderen). Die Sichtbarkeit wurde als weiteres Problem erwähnt, und da Singletons den "globalen" (= zufälligen) Zugriff auf den gemeinsam genutzten Status implizieren, können subtile Fehler auftreten, wenn sie in gleichzeitigen Anwendungen nicht ordnungsgemäß synchronisiert werden.

Ich halte es für ein Anti-Pattern, es ist ein schlechter objektorientierter Stil, der im Wesentlichen der Aufrechterhaltung des globalen Zustands gleichkommt.

Um auf Ihre Frage zurückzukommen:

Obwohl der App-Kontext selbst als Singleton betrachtet werden kann, wird er vom Framework verwaltet und verfügt über einen genau definierten Lebenszyklus , Gültigkeitsbereich und Zugriffspfad. Daher glaube ich, dass, wenn Sie den App-Global-Status verwalten müssen, dieser hier und nirgendwo anders abgelegt werden sollte. Überlegen Sie für alles andere, ob Sie wirklich ein Singleton-Objekt benötigen oder ob es auch möglich wäre, Ihre Singleton-Klasse neu zu schreiben, um stattdessen kleine, kurzlebige Objekte zu instanziieren, die die Aufgabe ausführen zur Hand.

292
Matthias

Ich empfehle Singletons sehr. Wenn Sie einen Singleton haben, der einen Kontext benötigt, haben Sie:

MySingleton.getInstance(Context c) {
    //
    // ... needing to create ...
    sInstance = new MySingleton(c.getApplicationContext());
}

Ich bevorzuge Singletons gegenüber Application, da dies dazu beiträgt, dass eine App viel übersichtlicher und modularer bleibt. Anstatt nur einen Ort zu haben, an dem der gesamte globale Status der App verwaltet werden muss, kann sich jedes einzelne Teil um sich selbst kümmern. Auch die Tatsache, dass Singletons (auf Anfrage) faul initialisieren, anstatt Sie auf den Weg zu führen, alle Initialisierungen von vornherein in Application.onCreate () durchzuführen, ist gut.

Es ist an sich nichts falsch daran, Singletons zu verwenden. Verwenden Sie sie einfach richtig, wenn es Sinn macht. Das Android Framework hat tatsächlich eine Menge davon, um prozessbezogene Caches geladener Ressourcen und ähnlicher Dinge zu verwalten.

Auch für einfache Anwendungen ist Multithreading für Singletons kein Problem, da standardmäßig alle Standard-Rückrufe für die App auf den Haupt-Thread des Prozesses verteilt werden, sodass kein Multithreading stattfindet, es sei denn, Sie führen es explizit über Threads oder ein implizit durch Veröffentlichen eines Inhaltsanbieters oder eines Dienstes IBinder für andere Prozesse.

Denken Sie nur darüber nach, was Sie tun. :)

227
hackbod

Von: Entwickler> Referenz - Anwendung

Normalerweise ist es nicht erforderlich, eine Unterklasse für die Anwendung festzulegen. In den meisten Fällen können statische Singletons die gleiche Funktionalität modularer bereitstellen. Wenn Ihr Singleton einen globalen Kontext benötigt (zum Beispiel zum Registrieren von Rundfunkempfängern), kann der Funktion zum Abrufen ein Kontext zugewiesen werden, der beim erstmaligen Erstellen des Singleton intern Context.getApplicationContext () verwendet.

20
Somatik

Ich hatte das gleiche Problem: Singleton oder eine Unterklasse Android.os.Application erstellen?

Zuerst habe ich es mit dem Singleton versucht, aber meine App ruft irgendwann den Browser auf

Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));

und das Problem ist, dass, wenn das Mobilteil nicht über genügend Speicher verfügt, die meisten Ihrer Klassen (sogar Singletons) bereinigt werden, um Speicher zu erhalten. Wenn Sie also vom Browser zu meiner App zurückkehren, stürzt es jedes Mal ab.

Lösung: Platzieren Sie die benötigten Daten in einer Unterklasse der Anwendungsklasse.

11
JoséMi

Die Anwendung ist nicht die gleiche wie beim Singleton. Die Gründe dafür sind:

  1. Die Methode der Anwendung (z. B. onCreate) wird im UI-Thread aufgerufen.
  2. singletons Methode kann in jedem Thread aufgerufen werden.
  3. In der Methode "onCreate" von Application können Sie den Handler instanziieren.
  4. Wenn der Singleton in einem Nicht-UI-Thread ausgeführt wird, können Sie den Handler nicht instanziieren.
  5. Die Anwendung verfügt über die Fähigkeit, den Lebenszyklus der Aktivitäten in der App zu verwalten. Sie verfügt über die Methode "registerActivityLifecycleCallbacks". Die Singletons verfügen jedoch nicht über die Fähigkeit.
10
sunhang

Betrachten Sie beide gleichzeitig:

  • singleton-Objekte als statische Instanzen innerhalb der Klassen haben.
  • eine gemeinsame Klasse (Context), die die Singleton-Instanzen für alle Singelton-Objekte in Ihrer Anwendung zurückgibt. Dies hat den Vorteil, dass die Methodennamen in Context beispielsweise folgende Bedeutung haben: context.getLoggedinUser () anstelle von User.getInstance ().

Außerdem empfehle ich Ihnen, Ihren Kontext so zu erweitern, dass er nicht nur den Zugriff auf einzelne Objekte enthält, sondern auch einige Funktionen, auf die global zugegriffen werden muss, wie beispielsweise context.logOffUser (), context.readSavedData () usw. Möglicherweise wird der Kontext in umbenannt Die Fassade würde dann Sinn machen.

5
adranale

Sie sind eigentlich die gleichen. Es gibt einen Unterschied, den ich sehen kann. Mit Application class können Sie Ihre Variablen in Application.onCreate () initialisieren und in Application.onTerminate () zerstören. Mit Singleton müssen Sie VM Statik initialisieren und zerstören.

4
Fedor

Aus dem sprichwörtlichen Maul eines Pferdes ...

Bei der Entwicklung Ihrer App ist es möglicherweise erforderlich, Daten, Kontext oder Dienste in Ihrer App global freizugeben. Wenn Ihre App beispielsweise Sitzungsdaten enthält, z. B. den derzeit angemeldeten Benutzer, möchten Sie diese Informationen wahrscheinlich offenlegen. In Android besteht das Muster zur Lösung dieses Problems darin, dass Ihre Android.app.Application-Instanz alle globalen Daten besitzt und Ihre Application-Instanz dann als Singleton mit statischen Zugriffsmechanismen auf die verschiedenen Daten und Dienste behandelt.

Wenn Sie eine Android - App schreiben, ist garantiert nur eine Instanz der Android.app.Application-Klasse vorhanden. Es ist daher sicher (und wird vom Google Android] - Team empfohlen), sie als Singleton zu behandeln . Das heißt, Sie können Ihrer Anwendungsimplementierung problemlos eine statische getInstance () - Methode hinzufügen. Wie so:

public class AndroidApplication extends Application {

    private static AndroidApplication sInstance;

    public static AndroidApplication getInstance(){
        return sInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sInstance = this;
    }
}
3
RMcGuigan

Meine 2 Cent:

Ich habe bemerkt, dass einige Singleton-/statische Felder zurückgesetzt wurden, als meine Aktivität zerstört wurde. Ich habe dies bei einigen Low-End-2.3-Geräten bemerkt.

Mein Fall war sehr einfach: Ich habe nur eine private Datei "init_done" und eine statische Methode "init", die ich von activity.onCreate () aufgerufen habe. Ich stelle fest, dass sich die Methode init bei einem Neuaufbau der Aktivität selbst neu ausführte.

Obwohl ich meine Bestätigung nicht beweisen kann, kann dies damit zusammenhängen, WANN der Singleton/die Klasse zuerst erstellt/verwendet wurde. Wenn die Aktivität zerstört/recycelt wird, scheinen alle Klassen, auf die sich nur diese Aktivität bezieht, ebenfalls recycelt zu werden.

Ich habe meine Instanz von Singleton in eine Unterklasse von Application verschoben. Ich greife auf sie von der Anwendungsinstanz aus zu. und bemerkte das Problem seitdem nicht mehr.

Ich hoffe das kann jemandem helfen.

3
Christ

Meine Aktivitätsaufrufe beenden () (was nicht sofort beendet wird, aber irgendwann erledigt wird) und Google Street Viewer aufrufen. Wenn ich es auf Eclipse debugge, wird meine Verbindung zur App unterbrochen, wenn Street Viewer aufgerufen wird. Dies wird als (vollständige) Anwendung verstanden, die geschlossen wird, um angeblich Speicher freizugeben (da eine einzelne abgeschlossene Aktivität dieses Verhalten nicht verursachen sollte). . Trotzdem kann ich den Status in einem Bundle über onSaveInstanceState () speichern und in der onCreate () -Methode der nächsten Aktivität im Stapel wiederherstellen. Entweder mit einem statischen Singleton oder einer Unterklassenanwendung wird die Anwendung geschlossen und der Status wird verloren (es sei denn, ich speichere sie in einem Bundle). Aus meiner Erfahrung sind sie also in Bezug auf die Erhaltung des Staates die gleichen. Mir ist aufgefallen, dass die Verbindung in Android 4.1.2 und 4.2.2, aber nicht in 4.0.7 oder 3.2.4 verloren gegangen ist, was meines Erachtens darauf hindeutet, dass sich der Speicherwiederherstellungsmechanismus in einigen Fällen geändert hat Punkt.

2
Piovezan