Android Studio:
Platzieren Sie Android-Kontextklassen nicht in statischen Feldern. Dies ist ein Speicherverlust (und bricht auch Instant Run)
Also 2 Fragen:
# 1 Wie ruft man startService
eine statische Methode ohne statische Variable für den Kontext auf?
# 2 Wie senden Sie einen localBroadcast von einer statischen Methode (gleich)?
Beispiele:
public static void log(int iLogLevel, String sRequest, String sData) {
if(iLogLevel > 0) {
Intent intent = new Intent(mContext, LogService.class);
intent.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW");
mContext.startService(intent);
}
}
oder
Intent intent = new Intent(MAIN_ACTIVITY_RECEIVER_INTENT);
intent.putExtra(MAIN_ACTIVITY_REQUEST_FOR_UPDATE, sRequest));
intent.putExtra(MAIN_ACTIVITY_DATA_FOR_VIEW, sData);
intent.putExtra(MAIN_ACTIVITY_LOG_LEVEL, iLogLevel);
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
Was wäre der richtige Weg, dies ohne zu tun mContext
?
HINWEIS: Ich denke, meine Hauptfrage könnte sein, wie der Kontext an eine Klasse übergeben werden kann, aus der die aufrufende Methode stammt.
android
android-studio-2.2
John Smith
quelle
quelle
Antworten:
Übergeben Sie es einfach als Parameter an Ihre Methode. Es macht keinen Sinn, eine statische Instanz von
Context
ausschließlich zum Starten einer zu erstellenIntent
.So sollte Ihre Methode aussehen:
Aktualisierung von Kommentaren zu Frage: Kaskadieren Sie den Kontext von der initiierenden Aktivität (über Konstruktorparameter oder Methodenparameter) bis zu dem Punkt, an dem Sie ihn benötigen.
quelle
MyClass
ein öffentlicher Konstruktor wie eine Methode istpublic MyClass(Context ctx) { // put this ctx somewhere to use later }
(Dies ist Ihr Konstruktor), erstellen Sie jetzt eine neue Instanz derMyClass
Verwendung dieses Konstruktors, z. B.MyClass mc = new MyClass(ctx);
Stellen Sie einfach sicher, dass Sie context.getApplicationContext () übergeben oder getApplicationContext () für jeden Kontext aufrufen, der über Methoden / Konstruktor an Ihren Singleton übergeben wird, wenn Sie ihn in einem Mitgliedsfeld speichern möchten.
Beispiel für einen idiotensicheren Beweis (selbst wenn jemand eine Aktivität übergeben würde, wird der App-Kontext erfasst und damit der Singleton instanziiert):
getApplicationContext () gemäß den Dokumenten: " Gibt den Kontext des einzelnen globalen Anwendungsobjekts des aktuellen Prozesses zurück."
Dies bedeutet, dass der von "getApplicationContext ()" zurückgegebene Kontext den gesamten Prozess durchläuft. Daher spielt es keine Rolle, ob Sie irgendwo einen statischen Verweis darauf speichern, da er zur Laufzeit Ihrer App immer vorhanden ist (und alle Objekte überlebt) / Singletons dadurch instanziiert).
Vergleichen Sie dies mit dem Kontext innerhalb von Ansichten / Aktivitäten, die große Datenmengen enthalten. Wenn Sie einen Kontext verlieren, der von einer Aktivität gehalten wird, kann das System diese Ressource nicht freigeben, was offensichtlich nicht gut ist.
Ein Verweis auf eine Aktivität nach ihrem Kontext sollte denselben Lebenszyklus wie die Aktivität selbst haben, andernfalls wird der Kontext als Geisel gehalten, was zu einem Speicherverlust führt (was der Grund für die Flusenwarnung ist).
BEARBEITEN: Für den Kerl, der das Beispiel aus den obigen Dokumenten verprügelt hat, gibt es im Code sogar einen Kommentarbereich über das, worüber ich gerade geschrieben habe:
quelle
Es ist nur eine Warnung. Mach dir keine Sorgen. Wenn Sie einen Anwendungskontext verwenden möchten, können Sie ihn in einer "Singleton" -Klasse speichern, mit der die gesamte Singleton-Klasse in Ihrem Projekt gespeichert wird.
quelle
In Ihrem Fall ist es nicht sehr sinnvoll, es als statisches Feld zu haben, aber ich denke nicht, dass es in allen Fällen schlecht ist. Wenn Sie jetzt wissen, was Sie tun, können Sie ein statisches Feld mit Kontext haben und es später auf Null setzen. Ich erstelle eine statische Instanz für meine Hauptmodellklasse, die einen Kontext enthält, deren Anwendungskontext kein Aktivitätskontext ist, und ich habe auch ein statisches Instanzfeld der Klasse, das Aktivität enthält, die ich beim Zerstören auf Null stelle. Ich sehe nicht, dass ich einen Speicherverlust habe. Also, wenn ein kluger Kerl denkt, ich liege falsch, kannst du gerne einen Kommentar abgeben ...
Auch Instant Run funktioniert hier gut ...
quelle
Vermeiden Sie im Allgemeinen, dass Kontextfelder als statisch definiert werden. Die Warnung selbst erklärt, warum: Es ist ein Speicherverlust. Sofortiger Lauf kann brechen nicht das größte Problem auf dem Planeten.
Nun gibt es zwei Szenarien, in denen Sie diese Warnung erhalten würden. Für eine Instanz (die offensichtlichste):
Und dann gibt es das etwas kniffligere, bei dem der Kontext in eine Klasse eingeschlossen ist:
Und diese Klasse ist irgendwo als statisch definiert:
Und du wirst die Warnung bekommen.
Die Lösung selbst ist recht einfach: Platzieren Sie keine Kontextfelder in statischen Instanzen , sei es die einer Wrapping-Klasse, oder deklarieren Sie sie direkt als statisch.
Die Lösung für die Warnung ist einfach: Platzieren Sie das Feld nicht statisch. Übergeben Sie in Ihrem Fall den Kontext als Instanz an die Methode. Verwenden Sie für Klassen, in denen mehrere Kontextaufrufe ausgeführt werden, einen Konstruktor, um den Kontext (oder eine entsprechende Aktivität) an die Klasse zu übergeben.
Beachten Sie, dass es sich um eine Warnung und nicht um einen Fehler handelt. Wenn Sie aus irgendeinem Grund einen statischen Kontext benötigen , können Sie dies tun. Dabei entsteht jedoch ein Speicherverlust.
quelle
Wenn Sie sicherstellen, dass es sich um einen Anwendungskontext handelt. Es ist wichtig. Füge das hinzu
quelle
Verwenden Sie
WeakReference
diese Option , um den Kontext in Singleton-Klassen zu speichern. Die Warnung wird gelöschtJetzt können Sie auf Kontext wie zugreifen
quelle