Ich habe gerade die Android Developer Site durchgesehen und den Aktivitätslebenszyklus aktualisiert. In jedem Codebeispiel gibt es neben den Methoden der Superklasse einen Kommentar mit der Aufschrift "Rufen Sie immer zuerst die Methode der Superklasse auf".
Obwohl dies im Erstellungshalbzyklus sinnvoll ist: onCreate, onStart und onResume, bin ich ein wenig verwirrt darüber, wie der Zerstörungshalbzyklus korrekt ausgeführt wird: onPause, onStop, onDestroy.
Es ist sinnvoll, zuerst die instanzspezifischen Ressourcen zu zerstören, bevor Superklassenressourcen zerstört werden, von denen die instanzspezifischen Ressourcen abhängen können, und nicht umgekehrt. In den Kommentaren wird jedoch etwas anderes vorgeschlagen. Was vermisse ich?
Bearbeiten : Da die Leute hinsichtlich der Absicht in der Frage verwirrt zu sein scheinen, möchte ich wissen, welche der folgenden Aussagen richtig ist? UND WARUM ?
1. Google schlägt vor
@Override
protected void onStop() {
super.onStop(); // Always call the superclass method first
//my implementation here
}
2. Der andere Weg
@Override
protected void onStop() {
//my implementation here
super.onStop();
}
quelle
Antworten:
Meiner Meinung nach: keine einzige Sache.
Diese Antwort von Mark (auch bekannt als CommonsWare on SO) beleuchtet das Problem: Link - Sollte der Aufruf der Superclass-Methode die erste Aussage sein? . Aber dann können Sie den folgenden Kommentar zu seiner Antwort sehen:
Zurück zum ersten Platz. Okay, schauen wir uns das aus einem anderen Blickwinkel an. Wir wissen, dass die Java-Sprachspezifikation keine Reihenfolge angibt, in der der Anruf
super.overridenMethod()
getätigt werden muss (oder ob der Anruf überhaupt getätigt werden muss).Im Falle einer Klassenaktivität sind
super.overridenMethod()
Anrufe erforderlich und werden erzwungen :mCalled
wird auf true gesetztActivity.onStop()
.Das einzige Detail, über das noch diskutiert werden muss, ist die Reihenfolge.
I also know that both work
Sicher. Sehen Sie sich den Methodenkörper für Activity.onPause () an:
Egal wie Sie den Anruf einlegen
super.onPause()
, Sie werden in Ordnung sein. Activity.onStop () hat einen ähnlichen Methodenkörper. Aber werfen Sie einen Blick auf Activity.onDestroy ():Hier kann die Reihenfolge möglicherweise von Bedeutung sein, je nachdem, wie Ihre Aktivität eingerichtet ist und ob der Aufruf
super.onDestroy()
den folgenden Code stören würde.Als letztes Wort
Always call the superclass method first
scheint die Aussage nicht viele Beweise zu haben, um sie zu stützen. Was (für die Aussage) schlimmer ist, ist, dass der folgende Code entnommen wurdeandroid.app.ListActivity
:Und aus LunarLander Beispielanwendung in Android SDK enthalten:
Zusammenfassung und Erwähnungen:
Benutzer Philip Sheard : Bietet ein Szenario, in dem ein Anruf
super.onPause()
verzögert werden muss, wenn eine Aktivität gestartet wirdstartActivityForResult(Intent)
. Das Einstellen des Ergebnisses mitsetResult(...)
aftersuper.onPause()
funktioniert nicht. Er erklärt dies später in den Kommentaren zu seiner Antwort.Benutzer Sherif elKhatib : Erklärt aus der Logik, warum die Superklasse zuerst ihre Ressourcen initialisieren und zuletzt ihre Ressourcen zerstören darf :
Er weist weiter darauf hin: Wenn eine untergeordnete Klasse in Bezug auf die Ressourcenabhängigkeit angemessen von der übergeordneten Klasse isoliert ist, müssen die
super.X()
Aufrufe keiner Auftragsspezifikation entsprechen.Sehen Sie seine Antwort auf dieser Seite durch ein Szenario zu lesen , wo die Platzierung des
super.onDestroy()
Anrufs nicht die Programmlogik beeinflussen.Aus einer Antwort von Mark :
Bob Kerns aus diesem Thread :
Benutzer Steve Benett macht auch darauf aufmerksam:
Benutzer Sunil Mishra bestätigt, dass die Reihenfolge (höchstwahrscheinlich) beim Aufrufen der Methoden der Aktivitätsklasse keine Rolle spielt. Er behauptet auch, dass das Aufrufen von Methoden der Oberklasse zuerst als bewährte Methode angesehen wird . Dies konnte ich jedoch nicht bestätigen.
Benutzer LOG_TAG : Erklärt , warum ein Aufruf an übergeordnete Klasse Konstruktor muss sonst die vor allem sein. Meiner Meinung nach trägt diese Erklärung nicht zur gestellten Frage bei.
Endnote : Vertrauen, aber überprüfen. Die meisten Antworten auf dieser Seite folgen diesem Ansatz, um festzustellen, ob die Anweisung
Always call the superclass method first
logisch abgesichert ist. Wie sich herausstellt, ist dies nicht der Fall. Zumindest nicht im Fall von Klassenaktivität. Im Allgemeinen sollte man den Quellcode der Superklasse durchlesen, um festzustellen, ob das Ordnen von Aufrufen der Methoden von Super erforderlich ist.quelle
onDestroy
andonStop
last ein sicherer Standard ist und dassonPause
es in einigen Fällen schwieriger sein kann? Könnten Sie das zuerst hinzufügen? Ich war versucht, die Antwort selbst zu bearbeiten, bin mir aber nicht sicher, ob diese Zusammenfassung korrekt ist.Da (Sie sagen) es sinnvoll ist, zuerst super onCreate aufzurufen: Denken Sie darüber nach.
Wenn ich erstellen möchte, erstellt My Super seine Ressourcen> Ich erstelle meine Ressourcen.
Umgekehrt: (eine Art Stapel)
Wenn ich zerstören will, zerstöre ich meine Ressourcen> Mein Super zerstört seine Ressourcen.
In diesem Sinne gilt es für einige Funktionen (onCreate / onDestroy, onResume / onPause, onStart / onStop). Natürlich erstellt onCreate Ressourcen und onDestroy gibt diese Ressourcen frei. Der gleiche Beweis gilt übrigens auch für die anderen Paare.
Betrachten wir eine von Ihnen heruntergeladene Bibliothek mit einer LocationActivity, die eine Funktion getLocation () enthält, die den Speicherort bereitstellt. Höchstwahrscheinlich muss diese Aktivität ihre Inhalte in onCreate () initialisieren, wodurch Sie gezwungen werden, zuerst die Datei super.onCreate aufzurufen. Das machst du schon, weil du denkst, dass es Sinn macht. Jetzt entscheiden Sie in Ihrem onDestroy, dass Sie den Speicherort irgendwo in den SharedPreferences speichern möchten. Wenn Sie zuerst super.onDestroy aufrufen, ist es bis zu einem gewissen Grad möglich, dass getLocation nach diesem Aufruf einen Nullwert zurückgibt, da die Implementierung von LocationActivity den Standortwert in onDestroy aufhebt. Die Idee ist, dass Sie es nicht beschuldigen würden, wenn dies passiert. Daher würden Sie am Ende super.onDestroy aufrufen, nachdem Sie mit Ihrem eigenen onDestroy fertig sind. Ich hoffe das macht ein bisschen Sinn.
Wenn das oben Gesagte Sinn macht, denken Sie daran, dass wir zu jedem Zeitpunkt eine Aktivität haben, die dem obigen Konzept entspricht. Wenn ich diese Aktivität erweitern möchte, werde ich wahrscheinlich genauso denken und aufgrund des gleichen genauen Arguments der gleichen Reihenfolge folgen.
Durch Induktion sollte jede Aktivität dasselbe tun. Hier ist eine gute abstrakte Klasse für eine Aktivität, die gezwungen ist, diese Regeln zu befolgen:
Was ist, wenn Ihre Aktivität
AnudeepBullaActivity
BaseActivity erweitert und ich späterSherifElKhatibActivity
eine Aktivität erstellen möchte, die Ihre Aktivität erweitert? In welcher Reihenfolge soll ich diesuper.do
Funktionen aufrufen ? Es ist letztendlich das Gleiche.Wie für Ihre Frage:
Ich denke, Google will uns sagen: Bitte rufen Sie den Super an, egal wo. Als allgemeine Praxis nennen Sie es natürlich am Anfang. Google hat natürlich die klügsten Ingenieure und Entwickler, daher haben sie wahrscheinlich gute Arbeit geleistet, um ihre Superanrufe zu isolieren und die untergeordneten Anrufe nicht zu stören.
Ich habe ein bisschen versucht und es ist wahrscheinlich nicht einfach (da es sich um Google handelt, versuchen wir, das Gegenteil zu beweisen), eine Aktivität zu erstellen, die einfach abstürzt, weil Wann super aufgerufen wird.
Warum?
Alles, was in diesen Funktionen ausgeführt wird, ist für die Aktivitätsklasse wirklich privat und würde niemals zu Konflikten mit Ihrer Unterklasse führen. Zum Beispiel (onDestroy)
mManagedCursors und mManagedDialogs sowie mSearchManager sind private Felder. Und keine der öffentlichen / geschützten APIs wird von dem, was hier getan wird, betroffen sein.
In API 14 wurde jedoch dispatchActivityDestroyed hinzugefügt, um onActivityDestroyed an die in Ihrer Anwendung registrierten ActivityLifecycleCallbacks zu senden. Daher hat jeder Code, der von einer Logik in Ihren ActivityLifecycleCallbacks abhängt, ein anderes Ergebnis, je nachdem, wann Sie den Super aufrufen. Beispielsweise:
Erstellen Sie eine Anwendungsklasse, die die Anzahl der aktuell ausgeführten Aktivitäten zählt:
Das Folgende mag keinen Sinn ergeben oder ist keine gute Praxis, aber es dient nur dazu, einen Punkt zu beweisen (man könnte eine realere Situation finden). Erstellen Sie die MainActivity, die angeblich zur GoodBye-Aktivität geht, wenn sie abgeschlossen ist und wenn es die letzte Aktivität ist:
Wenn Sie zu Beginn Ihres onDestroy super.onDestroy aufrufen, wird die GoodBye-Aktivität gestartet. Wenn Sie am Ende Ihres onDestroy super.onDestroy aufrufen, wird die GoodBye-Aktivität nicht gestartet.
Auch dies ist natürlich nicht das optimale Beispiel. Dies zeigt jedoch, dass Google hier etwas durcheinander gebracht hat. Alle anderen Variablen hätten das Verhalten Ihrer App nicht beeinflusst. Das Hinzufügen dieses Versands zu onDestroy führte jedoch dazu, dass der Super Ihre Unterklasse irgendwie störte.
Ich sage, sie haben auch aus einem anderen Grund durcheinander gebracht. Sie haben nicht nur (vor API 14) in den Superaufrufen nur das berührt, was endgültig und / oder privat ist, sondern sie haben auch verschiedene interne Funktionen (privat) aufgerufen, die dann wirklich die onPause ... -Funktionen ausgelöst haben.
Beispielsweise ist
performStop
function die aufgerufene Funktion, die wiederum die onStop-Funktion aufruft:Beachten Sie, dass sie irgendwo in dieser Funktion den onStop der Aktivität aufrufen. Daher haben sie möglicherweise auch den gesamten Code (in super.onStop enthalten) vor oder nach dem Aufruf von onStop eingefügt und dann Unterklassen über leere onStop-Superfunktionen benachrichtigt, ohne die SuperNotCalledException hinzuzufügen oder nach diesem Aufruf zu suchen.
Wenn sie diesen Versand an den ActivityLifeCycle im performDestroy aufgerufen hätten, anstatt ihn am Ende von super.onDestroy aufzurufen, wäre das Verhalten unserer Aktivität unabhängig davon, wann wir den super aufgerufen haben, dasselbe gewesen.
Auf jeden Fall ist dies das erste, was sie tun (ein bisschen falsch) und es ist nur in API 14.
quelle
super.on
wird wahrscheinlich nie Ihre Aktivität zum Absturz bringen.Aus Java-Sicht gibt es hier eine Lösung für diese Verwirrung:
Warum müssen this () und super () die erste Anweisung in einem Konstruktor sein?
Der Konstruktor der übergeordneten Klasse muss vor dem Konstruktor der Unterklasse aufgerufen werden. Dadurch wird sichergestellt, dass beim Aufrufen von Methoden für die übergeordnete Klasse in Ihrem Konstruktor die übergeordnete Klasse bereits korrekt eingerichtet wurde.
Was Sie versuchen, Argumente an den Superkonstruktor zu übergeben, ist völlig legal. Sie müssen diese Argumente nur inline konstruieren, während Sie dies tun, oder sie an Ihren Konstruktor übergeben und sie dann an Super übergeben:
Wenn der Compiler dies nicht erzwungen hat, können Sie Folgendes tun:
Es zeigt, dass Unterfelder tatsächlich vor der Oberklasse inilialisiert werden müssen! In der Zwischenzeit "verteidigt" uns die Java-Anforderung vor der Spezialisierung der Klasse, indem sie das Argument des Superkonstruktors spezialisiert
In Fällen, in denen eine übergeordnete Klasse einen Standardkonstruktor hat, wird der Aufruf von super vom Compiler automatisch für Sie eingefügt. Da jede Klasse in Java von Object erbt, muss der Objektkonstruktor irgendwie aufgerufen und zuerst ausgeführt werden. Das automatische Einfügen von super () durch den Compiler ermöglicht dies. Wenn Super zuerst angezeigt wird, wird erzwungen, dass Konstruktorkörper in der richtigen Reihenfolge ausgeführt werden: Objekt -> Übergeordnet -> Untergeordnet -> ChildOfChild -> SoOnSoForth
(1) Die Überprüfung, dass Super die erste Aussage ist, reicht nicht aus, um dieses Problem zu verhindern. Zum Beispiel könnten Sie "super (someMethodInSuper ())" setzen. in Ihrem Konstruktor. Dies versucht, auf eine Methode in der Oberklasse zuzugreifen, bevor sie erstellt wird, obwohl Super die erste Anweisung ist.
(2) Der Compiler scheint eine andere Prüfung durchzuführen, die allein ausreicht, um dieses Problem zu verhindern. Die Meldung lautet "kann nicht auf xxx verweisen, bevor der Supertyp-Konstruktor aufgerufen wurde". Daher ist es nicht erforderlich, zu überprüfen, ob Super die erste Anweisung ist
Bitte gehen Sie diese http://valjok.blogspot.in/2012/09/super-constructor-must-be-first.html durch
quelle
Das Wichtigste ist, dass
super.onPause()
implizit aufgerufen wirdsetResult(Activity.RESULT_CANCELED)
. AbersetResult
kann nur einmal aufgerufen werden, und alle nachfolgenden Anrufe ignoriert werden. Wenn Sie also ein Ergebnis auf die übergeordnete Aktivität zurückschieben möchten, müssen Sie sichsetResult
selbst anrufen , bevor Sie anrufensuper.onPause()
. Soweit ich weiß, ist das das größte Problem.quelle
super.onPause() implicitly calls setResult(Activity.RESULT_CANCELED)
. Könnten Sie sagen, woher Sie das haben?BEIDE sind IMO richtig
Laut den Dokumenten
Super
Methode sollte immer aufgerufen werden, wenn die Dokumentation dies ausdrücklich sagt.Sie können jedoch auswählen, wann die Super-Methode aufgerufen werden soll.
Blick auf die Quelle von
onPause
Daher egal bevor oder nachdem es aufgerufen wird. Du solltest gut sein.
Aber für die beste Vorgehensweise sollten Sie es zuerst aufrufen.
Ich empfehle es hauptsächlich als Schutzmechanismus: Wenn es eine Ausnahme gibt, wurde die
super
Instanzmethode bereits aufgerufen.Wenn Sie diese Aufrufe auch in die erste Zeile setzen, können Sie künftig Fehler vermeiden, z. B. das Löschen von Code in der Methode und das versehentliche Löschen des Aufrufs an die Superklasse.
quelle
Base Class
aber wenn Sie überschreiben, ist es erforderlich, dass Sie dassuper
andere aufrufen, das Sie haben werdenandroid.app.SuperNotCalledException
Sie sagen, dass Google Methode 1 vorschlägt, Dianne Hackborn, eine bekannte Android-Framework-Ingenieurin, schlägt jedoch vor, den Google Forum-Link anders zu lesen .
Es macht Sinn , die intuitive Superklasse aufrufen letzten wenn Zerstören eine Instanz in den onPause, OnStop und onDestroy Methoden und erste , wenn die Schaffung einer Instanz mit den Methoden der onCreate, onResume und onStart .
quelle
Das Super der Rückrufe wird benötigt, um die Aktivität intern für das System in den richtigen Zustand zu versetzen.
Angenommen, Sie starten Ihre Aktivität und onCreate wird vom System aufgerufen. Jetzt können Sie es überschreiben und zB Ihr Layout laden. Aber um des Systemflusses willen muss man super aufrufen, damit das System mit dem Standardverfahren fortfahren kann. Aus diesem Grund wird eine Ausnahme ausgelöst, wenn Sie sie nicht aufrufen.
Dies geschieht unabhängig von Ihrer Implementierung in onCreate. Es ist nur für das System wichtig. Wenn es keine ANR geben würde, könnten Sie in jedem Rückruf eine Endlosschleife haben, und die Aktivität würde in dieser gefangen werden. Das System weiß also, wann der Rückruf beendet wurde, und ruft dann den nächsten an.
Ich kenne nur eine Situation, in der das Timing des Superanrufs notwendig ist. Wenn Sie das Standardverhalten des Themas oder der Anzeige und dergleichen in onCreate ändern möchten, müssen Sie dies tun, bevor Sie super aufrufen, um einen Effekt zu sehen. Ansonsten gibt es bei AFAIK keinen Unterschied, zu welcher Zeit Sie es anrufen.
Aber damit das System das tut, was es am besten kann, wird das Super in die erste Zeile eines Rückrufs gefolgt von Ihrem Code gesetzt, wenn Sie keinen guten Grund haben, damit zu brechen.
quelle