Wie ist die richtige Reihenfolge beim Aufrufen von Superklassenmethoden in den Methoden onPause, onStop und onDestroy? und warum?

89

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();  
    }
Anudeep Bulla
quelle
1
Ich bin im zweiten Lager wegen der Abschaltmethoden. Ich bin im ersten Lager für Startmethoden.
Danny117
1
Das ist so ziemlich der Punkt. Ich konnte einfach nicht verstehen, wie sinnvoll es war, Methode 1 zum Herunterfahren zu verwenden.
Anudeep Bulla

Antworten:

106

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. Aber die Kommentare deuten auf etwas anderes hin. Was vermisse ich?

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:

Aber warum sagt das offizielle Dokument in onPause (): "Rufen Sie immer zuerst die Superklassenmethode auf"?

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 :

if (!mCalled) {
    throw new SuperNotCalledException(
        "Activity " + mComponent.toShortString() +
            " did not call through to super.onStop()");
}

mCalledwird auf true gesetzt Activity.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:

protected void onPause() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);

    // This is to invoke 
    // Application.ActivityLifecyleCallbacks.onActivityPaused(Activity)
    getApplication().dispatchActivityPaused(this);

    // The flag to enforce calling of this method
    mCalled = true;
}

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 ():

protected void onDestroy() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
    mCalled = true;

    // dismiss any dialogs we are managing.
    if (mManagedDialogs != null) {
        final int numDialogs = mManagedDialogs.size();
        for (int i = 0; i < numDialogs; i++) {
            final ManagedDialog md = mManagedDialogs.valueAt(i);
            if (md.mDialog.isShowing()) {
                md.mDialog.dismiss();
            }
        }
        mManagedDialogs = null;
    }

    // close any cursors we are managing.
    synchronized (mManagedCursors) {
        int numCursors = mManagedCursors.size();
        for (int i = 0; i < numCursors; i++) {
            ManagedCursor c = mManagedCursors.get(i);
            if (c != null) {
                c.mCursor.close();
            }
        }
        mManagedCursors.clear();
    }

    // Close any open search dialog
    if (mSearchManager != null) {
        mSearchManager.stopSearch();
    }

    getApplication().dispatchActivityDestroyed(this);
}

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 firstscheint 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 wurde android.app.ListActivity:

public class ListActivity extends Activity {

    ....

    @Override
    protected void onDestroy() {
        mHandler.removeCallbacks(mRequestFocus);
        super.onDestroy();
    }
    ....    
}

Und aus LunarLander Beispielanwendung in Android SDK enthalten:

public class LunarLander extends Activity {

    ....

    @Override
    protected void onPause() {
        mLunarView.getThread().pause(); // pause game when Activity pauses
        super.onPause();
    }
    ....
}

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 wird startActivityForResult(Intent). Das Einstellen des Ergebnisses mit setResult(...) after super.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 :

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.

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 :

Von Ihnen überschriebene Methoden, die Teil der Komponentenerstellung sind (onCreate (), onStart (), onResume () usw.), sollten Sie als erste Anweisung an die Oberklasse ketten , um sicherzustellen, dass Android die Möglichkeit hat, seine Arbeit vor Ihnen zu erledigen Versuchen Sie, etwas zu tun, das davon abhängt, dass diese Arbeit erledigt wurde.

Von Ihnen überschriebene Methoden, die Teil der Komponentenzerstörung sind (onPause (), onStop (), onDestroy () usw.), sollten Sie zuerst arbeiten und als letztes an die Oberklasse ketten . Auf diese Weise haben Sie Ihre Arbeit zuerst erledigt, falls Android etwas bereinigt, von dem Ihre Arbeit abhängt.

Bei Methoden, die etwas anderes als void zurückgeben (onCreateOptionsMenu () usw.), verketten Sie manchmal die Oberklasse in der return-Anweisung, vorausgesetzt, Sie tun nicht speziell etwas, das einen bestimmten Rückgabewert erzwingen muss.

Alles andere - wie onActivityResult () - liegt im Großen und Ganzen bei Ihnen. Ich neige dazu, mich als erstes an die Oberklasse zu ketten, aber wenn Sie nicht auf Probleme stoßen, sollte eine spätere Verkettung in Ordnung sein.

Bob Kerns aus diesem Thread :

Es ist ein gutes Muster [(das Muster, das Mark oben vorschlägt)], aber ich habe einige Ausnahmen gefunden. Zum Beispiel würde das Thema , das ich auf meine PreferenceActivity anwenden wollte, nur wirksam, wenn ich es vor onCreate () der Oberklasse stelle.

Benutzer Steve Benett macht auch darauf aufmerksam:

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.

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 firstlogisch 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.

Vikram
quelle
2
Beeindruckend. Danke für die Hinweise. Sowohl diese als auch die Antworten von @ Sherif bieten einen wichtigen Kontext. Wenn einer von Ihnen die Antworten auf dieser Seite zusammenfassen kann, würde ich sie als akzeptiert markieren. Bitte geben Sie Folgendes an: 1.Antworten auf dieser Seite. 2. @ Philipps Antwort auf dieser Seite 3. @ CommonsWares Antwort auf dieser Seite 4. Diese Diskussion würde ich, aber ich möchte nicht die Credits für Ihre wunderbaren Antworten. Prost & Danke
Anudeep Bulla
Hallo. Könnten Sie bitte zusammenfassen, da @Sherif nicht will?
Anudeep Bulla
@ AnudeepBulla Hallo Anudeep, gib mir bis morgen. Ich werde das relevante Material zu meiner Antwort hinzufügen und Ihnen hier einen Kommentar hinterlassen.
Vikram
@AnudeepBulla Ich habe oben eine Zusammenfassung hinzugefügt. Bitte lassen Sie es mich wissen, falls ich etwas verpasst habe.
Vikram
@ Vikram Ist die TL; DR. dass calling onDestroyand onStoplast ein sicherer Standard ist und dass onPausees 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.
Blaisorblade
12

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:

package mobi.sherif.base;

import android.app.Activity;
import android.os.Bundle;

public abstract class BaseActivity extends Activity {
    protected abstract void doCreate(Bundle savedInstanceState);
    protected abstract void doDestroy();
    protected abstract void doResume();
    protected abstract void doPause();
    protected abstract void doStart();
    protected abstract void doStop();
    protected abstract void doSaveInstanceState(Bundle outState);
    @Override
    protected final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        doCreate(savedInstanceState);
    }
    @Override
    protected final void onDestroy() {
        doDestroy();
        super.onDestroy();
    }
    @Override
    protected final void onResume() {
        super.onResume();
        doResume();
    }
    @Override
    protected final void onPause() {
        doPause();
        super.onPause();
    }
    @Override
    protected final void onStop() {
        doStop();
        super.onStop();
    }
    @Override
    protected final void onStart() {
        super.onStart();
        doStart();
    }
    @Override
    protected final void onSaveInstanceState(Bundle outState) {
        doSaveInstanceState(outState);
        super.onSaveInstanceState(outState);
    }
}

Was ist, wenn Ihre Aktivität AnudeepBullaActivityBaseActivity erweitert und ich später SherifElKhatibActivityeine Aktivität erstellen möchte, die Ihre Aktivität erweitert? In welcher Reihenfolge soll ich die super.doFunktionen 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)

protected void onDestroy() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
    mCalled = true;

    // dismiss any dialogs we are managing.
    if (mManagedDialogs != null) {
        final int numDialogs = mManagedDialogs.size();
        for (int i = 0; i < numDialogs; i++) {
            final ManagedDialog md = mManagedDialogs.valueAt(i);
            if (md.mDialog.isShowing()) {
                md.mDialog.dismiss();
            }
        }
        mManagedDialogs = null;
    }

    // close any cursors we are managing.
    synchronized (mManagedCursors) {
        int numCursors = mManagedCursors.size();
        for (int i = 0; i < numCursors; i++) {
            ManagedCursor c = mManagedCursors.get(i);
            if (c != null) {
                c.mCursor.close();
            }
        }
        mManagedCursors.clear();
    }

    // Close any open search dialog
    if (mSearchManager != null) {
        mSearchManager.stopSearch();
    }

    getApplication().dispatchActivityDestroyed(this);
}

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:

package mobi.shush;

import android.app.Activity;
import android.app.Application;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;

public class SherifApplication extends Application implements ActivityLifecycleCallbacks {
    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(this);
    }
    public int getCount() {
        return count;
    }
    int count = 0;
    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        count++;
    }
    @Override
    public void onActivityDestroyed(Activity activity) {
        count--;
    }
    @Override
    public void onActivityPaused(Activity activity) {}
    @Override
    public void onActivityResumed(Activity activity) {}
    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState)           {}
    @Override
    public void onActivityStarted(Activity activity) {}
    @Override
    public void onActivityStopped(Activity activity) {}
}

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:

@Override
protected void onDestroy() {
    super.onDestroy();
    if(((SherifApplication) getApplication()).getCount() == 0) {
        //i want to go to a certain activity when there are no other activities
        startActivity(new Intent(this, GoodBye.class));
    }
}

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 performStopfunction die aufgerufene Funktion, die wiederum die onStop-Funktion aufruft:

final void performStop() {
    if (mLoadersStarted) {
        mLoadersStarted = false;
        if (mLoaderManager != null) {
            if (!mChangingConfigurations) {
                mLoaderManager.doStop();
            } else {
                mLoaderManager.doRetain();
            }
        }
    }

    if (!mStopped) {
        if (mWindow != null) {
            mWindow.closeAllPanels();
        }

        if (mToken != null && mParent == null) {
            WindowManagerGlobal.getInstance().setStoppedState(mToken, true);
        }

        mFragments.dispatchStop();

        mCalled = false;
        mInstrumentation.callActivityOnStop(this);
        if (!mCalled) {
            throw new SuperNotCalledException(
                    "Activity " + mComponent.toShortString() +
                    " did not call through to super.onStop()");
        }

        synchronized (mManagedCursors) {
            final int N = mManagedCursors.size();
            for (int i=0; i<N; i++) {
                ManagedCursor mc = mManagedCursors.get(i);
                if (!mc.mReleased) {
                    mc.mCursor.deactivate();
                    mc.mReleased = true;
                }
            }
        }

        mStopped = true;
    }
    mResumed = false;
}

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.

Sherif elKhatib
quelle
Die Frage war nie, warum es Sinn macht, super.onDestroy () zuletzt aufzurufen. Ich liebe dein Bibliotheksbeispiel. Genau das wollte ich auch vermitteln. Ich könnte mich nicht mehr darauf einigen, Super-Methoden zuletzt auf die letzten Zerstörungshalbzyklen aufzurufen, genau wie in einem Stapel, um einen versehentlichen Datenverlust zu verhindern. Das Problem ist, warum Google angesichts der oben genannten Prämisse darauf besteht, zuerst Supermethoden aufzurufen. Ich habe die Frage gestellt, weil ich dachte, dass ich und anscheinend auch Sie es vielleicht ganz anders angehen. Prost
Anudeep Bulla
Oh, ich habe die Vorschläge von Google nicht gesehen und den anderen Weg: p! Hören Sie, ich werde versuchen, eine Aktivität zu erstellen, die abstürzt, wenn Sie zuerst onDestroy aufrufen. Das sollten Sie auch versuchen. Prost
Sherif elKhatib
@ AnudeepBulla können Sie meine Änderungen überprüfen. Und übrigens können Sie aufhören, es zu versuchen. super.onwird wahrscheinlich nie Ihre Aktivität zum Absturz bringen.
Sherif elKhatib
Beeindruckend. Danke für die Hinweise. Sowohl diese als auch die Antworten des @ Benutzers bieten einen wichtigen Kontext. Wenn einer von Ihnen die Antworten auf dieser Seite zusammenfassen kann, würde ich sie als akzeptiert markieren. Bitte geben Sie Folgendes an: 1.Antworten auf dieser Seite. 2. @ Philipps Antwort auf dieser Seite 3. @ CommonsWares Antwort auf dieser Seite 4. Diese Diskussion würde ich, aber ich möchte nicht die Credits für Ihre wunderbaren Antworten. Prost & Danke
Anudeep Bulla
@ AnudeepBulla Gern geschehen. Ich bin mir nicht sicher, wie wir entscheiden sollen, wer die endgültige Beschreibung veröffentlicht.
Vikram
1

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:

public MySubClassB extends MyClass {
        public MySubClassB(Object[] myArray) {
                super(myArray);
        }
}

Wenn der Compiler dies nicht erzwungen hat, können Sie Folgendes tun:

public MySubClassB extends MyClass {
        public MySubClassB(Object[] myArray) {
                someMethodOnSuper(); //ERROR super not yet constructed
                super(myArray);
        }
}

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

LOG_TAG
quelle
Ich verstehe vollkommen, was Sie da rausbringen. Sie rufen zuerst Superklassenkonstruktoren auf, weil sie möglicherweise Ressourcen initialisieren, die das Kind möglicherweise benötigt. und die Zerstörer zuletzt, weil du wahrscheinlich nicht alle Eltern für die lokalen Ressourcen löschen willst, was sie sinnlos macht. Das ist genau mein Punkt. Und da onPause, onStop und onDestroy die Aufgabe haben, Statusinformationen zu speichern und GC mehr oder weniger Ressourcen zur Verfügung zu stellen (sie in gewissem Sinne zu zerstören), sehe ich sie analog zu Destruktoren und halte es daher für sinnvoll, sie zuletzt zu nennen. Nein?
Anudeep Bulla
Alles, was Sie oben gesagt haben, ist genau das, was ich gemeint habe, als ich sagte, "das Aufrufen von Supermethoden macht im Erstellungshalbzyklus zuerst Sinn". Ich bin besorgt und verwirrt im Fall der Zerstörungshalbzyklusmethoden, die eher Destruktoren entsprechen. Prost
Anudeep Bulla
1

Das Wichtigste ist, dass super.onPause()implizit aufgerufen wird setResult(Activity.RESULT_CANCELED). Aber setResultkann 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 sich setResultselbst anrufen , bevor Sie anrufen super.onPause(). Soweit ich weiß, ist das das größte Problem.

Philip Sheard
quelle
Wow, das scheint wichtig zu sein. Es gibt also eine Situation, in der Sie den Aufruf der Super-Methoden definitiv verzögern müssen. Danke dir.
Anudeep Bulla
super.onPause() implicitly calls setResult(Activity.RESULT_CANCELED). Könnten Sie sagen, woher Sie das haben?
Vikram
Ich war verwirrt. Es ist tatsächlich finish (), das setResult aufruft, und super.onBackPressed () ruft finish () auf. SetResult muss also unbedingt vor super.onBackPressed () aufgerufen werden. Ich bin nicht sicher, ob es Umstände gibt, unter denen super.onPause () dazu führen könnte, dass setResult aufgerufen wird, aber ich ziehe es vor, es nicht zu riskieren.
Philip Sheard
1

BEIDE sind IMO richtig

Laut den Dokumenten

Abgeleitete Klassen müssen die Implementierung dieser Methode durch die Superklasse aufrufen. Ist dies nicht der Fall, wird eine Ausnahme ausgelöst.

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

protected void onPause() {
    getApplication().dispatchActivityPaused(this);
    mCalled = true;
}

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 superInstanzmethode 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.

Sunil Mishra
quelle
Es tut mir leid, wenn die Frage beim ersten Mal nicht ganz klar war, aber schauen Sie sie sich jetzt bitte an.
Anudeep Bulla
@ AnudeepBulla Das habe ich dir erklärt. Sie können beide verwenden. Beide sind gültig.
Sunil Mishra
Nach meinem Verständnis ist eine benutzerdefinierte Implementierung der Methoden onPause, onStop und onDestroy nicht unbedingt erforderlich. Ich habe reichlich Apps ohne diese gemacht. Was meinst du mit Super Methoden sollte immer aufgerufen werden? Sie werden implizit aufgerufen, auch ohne sie zu überschreiben. Ich weiß auch, dass beide funktionieren. Ich möchte wissen, warum die Dokumente sagen, dass Super zuerst aufgerufen werden sollte. Und falls die Frage immer noch nicht ersichtlich ist, erklären Sie bitte WARUM, wenn Sie sagen "Aber für bewährte Verfahren sollten Sie sie zuerst anrufen"?
Anudeep Bulla
Wenn Sie nicht überschreiben, werden die Methoden von aufgerufen, Base Classaber wenn Sie überschreiben, ist es erforderlich, dass Sie das superandere aufrufen, das Sie haben werdenandroid.app.SuperNotCalledException
Sunil Mishra
1
Sie scheinen falsch zu verstehen. Die Frage ist nicht, ob man anrufen soll oder nicht. Wie Sie bereits betont haben, MÜSSEN Sie dies tun, wenn Sie sie überschreiben. Die Frage ist, wann?
Anudeep Bulla
1

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 .

NickT
quelle
Der Link zu Dianne Hackborns Beitrag ist wichtig und bestätigt das Muster.
Nick Westgate
0

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.

Steve Benett
quelle
Die Reihenfolge in onCreate scheint ziemlich verständlich zu sein. Was passiert bei den Zerstörungsmethoden? Sagen Sie onStop. Angenommen, meine onStop-Implementierung verwendet einige der Ressourcen, die die Super-Methode freigibt, wenn sie aufgerufen wird. Dann ist es sinnvoll, die Super-Methode nach meiner Implementierung aufzurufen.
Anudeep Bulla
Im Idealfall sollte dies der Fall sein, richtig. Unsere Aktivität wird immer Ressourcen haben, über die die Superklasse verfügt, und einige mehr. Und diejenigen, die von meiner Aktivität unabhängig sind, können in den meisten Fällen von den gemeinsamen Ressourcen der Superklasse abhängen. Es ist sinnvoller, zuerst mit meinen Ressourcen umzugehen und dann die Oberklasse anzurufen, um mit den gemeinsamen Ressourcen umzugehen. Warum sagt Google dann, wir sollten zuerst Methoden der Oberklasse aufrufen?
Anudeep Bulla
Über welche Ressource sprechen Sie, auf die Sie in onCreate zugreifen können, jedoch nicht in onDestroy?
Steve Benett
Ich habe keinen Anwendungsfall. Ich frage mich nur, wie es mit dem OOP-Stil variiert. Super-Klassen-Konstruktoren werden vor Ihrer Implementierung zuerst aufgerufen, und Super-Klassen-Destruktoren werden zuletzt nach Ihrer Implementierung aufgerufen, oder? onPause, onStop und onDestroy sind keine strengen Destruktoren, aber sie neigen dazu, dasselbe zu tun, oder? Zumindest onDestroy und meistens auch onStop .. nein?
Anudeep Bulla
Sehen Sie die Rückrufe in der Zustandsänderungsweise nicht als Konstruktor / Destruktor. Jeder Rückruf hat das Bedürfnis, zB eine Aktivität zu erstellen (gebrauchsfertig) / zu zerstören (Ihre letzte Chance zu interagieren) oder sie in den Vordergrund / Hintergrund zu stellen. Mit den Rückrufen können Sie Ihre Ressourcen im Systemfluss steuern. Das System prüft nur, in welchem ​​Zustand es sich befindet und behandelt entsprechend. Die von Ihnen verwendeten und die vom System gesteuerten Ressourcen sind unabhängig voneinander und es gibt keine Überschneidungen.
Steve Benett