Qual è l'ordine corretto per chiamare i metodi della superclasse nei metodi onPause, onStop e onDestroy? e perché?


92

Stavo visitando il sito per sviluppatori Android, aggiornando il ciclo di vita dell'attività e in ogni esempio di codice c'è un commento accanto ai metodi della super classe che dice "Chiama sempre prima il metodo della superclasse".

Anche se questo ha senso nel mezzo ciclo di creazione: onCreate, onStart e onResume, sono un po 'confuso su quale sia la procedura corretta nel mezzo ciclo di distruzione: onPause, onStop, onDestroy.

Distruggere prima le risorse specifiche dell'istanza, prima di distruggere le risorse della superclasse da cui possono dipendere le risorse specifiche dell'istanza ha senso, non il contrario, ma i commenti suggeriscono il contrario. Cosa mi sto perdendo?

Modifica : poiché le persone sembrano essere confuse sull'intento della domanda, quello che voglio sapere è quale delle seguenti affermazioni è corretta? E PERCHÉ ?

1.Google suggerisce

    @Override
    protected void onStop() {
      super.onStop();  // Always call the superclass method first

      //my implementation here
    }

2. L'altro modo

    @Override
    protected void onStop() {
       //my implementation here

       super.onStop();  
    }

1
Sono nel secondo campo per i metodi di spegnimento. Sono nel primo campo per i metodi di avvio.
danny117

1
Questo è più o meno il punto. Non riuscivo a capire come avesse senso usare il metodo 1 per i metodi di spegnimento.
Anudeep Bulla

Risposte:


109

Distruggere prima le risorse specifiche dell'istanza, prima di distruggere le risorse della superclasse da cui possono dipendere le risorse specifiche dell'istanza ha senso, non il contrario. Ma i commenti suggeriscono il contrario. Cosa mi manca?

Secondo me: non una cosa sola.

Questa risposta di Mark (aka CommonsWare su SO) fa luce sulla questione: Link - La chiamata al metodo della superclasse dovrebbe essere la prima affermazione? . Ma poi, puoi vedere il seguente commento lasciato sulla sua risposta:

Ma perché il documento ufficiale dice: "Chiama sempre prima il metodo della superclasse" in onPause ()?

Torna al punto di partenza. Ok, guardiamo questo da un'altra angolazione. Sappiamo che Java Language Specification non specifica un ordine in cui super.overridenMethod()deve essere effettuata la chiamata a (o se la chiamata deve essere effettuata).

In caso di attività in classe, le super.overridenMethod()chiamate sono richieste e applicate :

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

mCalledè impostato su true in Activity.onStop().

Ora, l'unico dettaglio rimasto su cui discutere è l'ordinamento.

I also know that both work

Sicuro. Guarda il corpo del metodo per Activity.onPause ():

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;
}

In qualunque modo tu inserisca la chiamata super.onPause(), starai bene. Activity.onStop () ha un corpo del metodo simile. Ma dai un'occhiata a 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);
}

Qui, l'ordinamento potrebbe possibilmente importa a seconda di come la vostra attività è messa a punto, e se chiamando super.onDestroy()interferirebbe con il codice che segue.

Come ultima parola, l'affermazione Always call the superclass method firstnon sembra avere molte prove a sostegno. Quel che è peggio (per l'affermazione) è che il seguente codice è stato preso da android.app.ListActivity:

public class ListActivity extends Activity {

    ....

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

E, dall'applicazione di esempio LunarLander inclusa in Android SDK:

public class LunarLander extends Activity {

    ....

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

Sintesi e menzioni meritevoli:

Utente Philip Sheard : fornisce uno scenario in cui una chiamata a super.onPause()deve essere ritardata nel caso in cui un'attività inizi a utilizzare startActivityForResult(Intent). L'impostazione del risultato utilizzando setResult(...) dopo super.onPause() non funzionerà. Successivamente chiarisce questo aspetto nei commenti alla sua risposta.

Utente Sherif elKhatib : spiega perché lasciare che la superclasse inizializzi prima le sue risorse e poi distrugga le sue risorse segue dalla logica:

Prendiamo in considerazione una libreria scaricata che ha una LocationActivity che contiene una funzione getLocation () che fornisce la posizione. Molto probabilmente, questa attività dovrà inizializzare le sue cose in onCreate () che ti costringerà a chiamare prima super.onCreate . Lo fai già perché senti che ha senso. Ora, nel tuo onDestroy, decidi di salvare la posizione da qualche parte nelle SharedPreferences. Se chiami prima super.onDestroy, è in una certa misura possibile che getLocation restituisca un valore nullo dopo questa chiamata perché l'implementazione di LocationActivity annulla il valore di posizione in onDestroy. L'idea è che non lo biasimeresti se questo accade.Pertanto, chiameresti super.onDestroy alla fine dopo aver finito con il tuo onDestroy.

Prosegue sottolineando: se una classe figlia è adeguatamente isolata (in termini di dipendenza dalle risorse) dalla classe genitore, la super.X() chiamate non devono aderire a nessuna specifica dell'ordine.

Vedi la sua risposta in questa pagina per leggere uno scenario in cui il posizionamento della super.onDestroy()chiamata fa influisce sulla logica del programma.

Da una risposta di Marco :

Metodi che sovrascrivi che fanno parte della creazione del componente (onCreate (), onStart (), onResume (), ecc.), Dovresti concatenare alla superclasse come prima istruzione , per assicurarti che Android abbia la possibilità di fare il suo lavoro prima di te tentare di fare qualcosa che si basi su quel lavoro che è stato fatto.

Metodi che sovrascrivi che fanno parte della distruzione dei componenti (onPause (), onStop (), onDestroy (), ecc.), Dovresti prima fare il tuo lavoro e concatenare alla superclasse come ultima cosa . In questo modo, nel caso in cui Android ripulisca qualcosa da cui dipende il tuo lavoro, avrai fatto prima il tuo lavoro.

Metodi che restituiscono qualcosa di diverso da void (onCreateOptionsMenu (), ecc.), A volte si concatena alla superclasse nell'istruzione return, assumendo che non si stia facendo specificamente qualcosa che deve forzare un particolare valore di ritorno.

Tutto il resto, come onActivityResult (), dipende da te, nel complesso. Tendo a concatenarmi alla superclasse come prima cosa, ma a meno che tu non abbia problemi, il concatenamento in seguito dovrebbe andare bene.

Bob Kerns da questo thread :

È un buon modello [(lo schema suggerito da Mark sopra)], ma ho trovato alcune eccezioni. Ad esempio, il tema che volevo applicare alla mia PreferenceActivity non avrebbe avuto effetto a meno che non lo mettessi prima di onCreate () della superclasse.

L'utente Steve Benett porta anche l'attenzione su questo:

Conosco solo una situazione, in cui è necessario il tempismo della super chiamata. Se vuoi modificare il comportamento standard del tema o del display e simili in onCreate, devi farlo prima di chiamare super per vedere un effetto . Altrimenti, AFAIK non c'è differenza a che ora lo chiami.

L'utente Sunil Mishra conferma che l'ordine (molto probabilmente) non gioca un ruolo quando si chiamano i metodi della classe Activity. Afferma inoltre che chiamare prima i metodi della superclasse è considerata una best practice . Tuttavia, non ho potuto confermarlo.

LOG_TAG utente : spiega perché una chiamata al costruttore della superclasse deve essere prima di tutto il resto. A mio parere, questa spiegazione non si aggiunge alla domanda che viene posta.

Nota finale : fidati, ma verifica. La maggior parte delle risposte in questa pagina seguono questo approccio per vedere se l'affermazione Always call the superclass method firstha un supporto logico. A quanto pare, non lo fa; almeno, non nel caso di attività in classe. In generale, si dovrebbe leggere il codice sorgente della superclasse per determinare se l'ordinamento delle chiamate ai metodi di super è un requisito.


2
Wow. Grazie per i suggerimenti. Sia questa che le risposte di @ Sherif forniscono un contesto importante. Se uno di voi può riassumere le risposte in questa pagina, la contrassegnerei come accettata. Si prega di includere: 1. Risposte in questa pagina. 2. Risposta di @ Philip su questa pagina 3. Risposta di @ CommonsWare su questa pagina 4. Questa discussione lo farei, ma non voglio i crediti per le tue meravigliose risposte. Cheers & Thanks
Anudeep Bulla

Ciao. Potresti riassumere, visto che @Sherif non vuole?
Anudeep Bulla

@AnudeepBulla Ciao Anudeep, dammi fino a domani. Aggiungerò il materiale pertinente alla mia risposta e ti lascio un commento qui.
Vikram

@AnudeepBulla ho aggiunto un riepilogo sopra. Per favore fatemi sapere nel caso mi sia perso qualcosa.
Vikram

@Vikram è il TL; DR. quella chiamata onDestroye onStopultima è un'impostazione predefinita più sicura e che per le onPausecose può essere più complicata in alcuni casi? Potresti aggiungerlo prima? Sono stato tentato di modificare la risposta da solo, ma non sono sicuro che questo riepilogo sia corretto.
Blaisorblade,

13

Dal momento che (dici) ha senso chiamare prima super onCreate: pensaci.

Quando voglio creare, il mio super crea le sue risorse> io creo le mie risorse.

Inversamente: (una specie di pila)

Quando voglio distruggere, distruggo le mie risorse> Il mio super distrugge le sue risorse.


In questo senso, si applica a qualsiasi coppia di funzioni (onCreate / onDestroy, onResume / onPause, onStart / onStop). Naturalmente, onCreate creerà risorse e onDestroy libererà queste risorse. A proposito, la stessa prova vale per le altre coppie.

Si consideri una libreria scaricata che ha una LocationActivity che contiene una funzione getLocation () che fornisce la posizione. Molto probabilmente, questa attività dovrà inizializzare il suo contenuto in onCreate () che ti costringerà a chiamare prima super.onCreate. Lo fai già perché senti che ha senso. Ora, nel tuo onDestroy, decidi di salvare la posizione da qualche parte nelle SharedPreferences. Se chiami prima super.onDestroy, è in una certa misura possibile che getLocation restituisca un valore nullo dopo questa chiamata perché l'implementazione di LocationActivity annulla il valore di posizione in onDestroy. L'idea è che non lo biasimeresti se ciò accadesse. Pertanto, chiameresti super.onDestroy alla fine dopo aver finito con il tuo onDestroy. Spero che questo abbia un senso.

Se quanto sopra ha senso, considera che in qualsiasi momento abbiamo un'attività che si attiene al concetto di cui sopra. Se voglio estendere questa attività, probabilmente mi sentirò allo stesso modo e seguirò lo stesso ordine a causa dello stesso identico argomento.

Per induzione, qualsiasi attività dovrebbe fare la stessa cosa. Ecco una buona lezione astratta per un'attività costretta a seguire queste regole:

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);
    }
}

Infine, cosa succede se la tua attività chiamata AnudeepBullaActivityestende BaseActivity e in seguito voglio creare SherifElKhatibActivityche estenda la tua attività? In quale ordine devo chiamare le super.dofunzioni? In definitiva è la stessa cosa.


Per quanto riguarda la tua domanda:

Penso che l'intenzione di Google sia di dirci: chiama il super, non importa dove. Come pratica generale, ovviamente, chiamala all'inizio. Google ovviamente ha gli ingegneri e gli sviluppatori più brillanti, quindi probabilmente hanno fatto un buon lavoro isolando le loro super chiamate e non interferendo con le chiamate dei bambini.

Ho provato un po 'e probabilmente non è facile (dato che è Google che stiamo cercando di dimostrare che si sbaglia) creare un'attività che si arresti facilmente a causa di quando viene chiamato super.

Perché?

Qualunque cosa fatta in queste funzioni è veramente privata per la classe Activity e non causerebbe mai alcun conflitto con la tua sottoclasse. Ad esempio (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, mManagedDialogs e mSearchManager sono tutti campi privati. E nessuna delle API pubbliche / protette sarà influenzata da ciò che viene fatto qui.

Tuttavia, nell'API 14, dispatchActivityDestroyed è stato aggiunto per inviare un onActivityDestroyed agli ActivityLifecycleCallback registrati nella tua applicazione. Pertanto, qualsiasi codice che dipenda da una logica nei tuoi ActivityLifecycleCallbacks avrà un risultato diverso in base a quando chiami il super. Per esempio:

Creare una classe di applicazione che conti il ​​numero di attività attualmente in esecuzione:

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) {}
}

Quanto segue potrebbe non avere senso o non è quello di una buona pratica, ma è solo per dimostrare un punto (si potrebbe trovare una situazione più reale). Crea la MainActivity che presumibilmente va all'attività GoodBye quando è terminata e quando è l'ultima attività:

@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));
    }
}

Se chiami super.onDestroy all'inizio del tuo onDestroy, verrà lanciata l'attività GoodBye. Se chiami super.onDestroy alla fine del tuo onDestroy, l'attività GoodBye non verrà avviata.

Naturalmente, ancora una volta, questo non è l'esempio ottimale. Tuttavia questo mostra che Google ha incasinato un po 'qui. Qualsiasi altra variabile non avrebbe influenzato il comportamento della tua app. Tuttavia, l'aggiunta di queste spedizioni a onDestroy ha causato l'interferenza del super in qualche modo con la tua sottoclasse.

Dico che hanno fatto casino anche per un motivo diverso. Non solo (prima dell'api 14) nelle chiamate super toccavano solo ciò che è final e / o private, ma chiamavano anche diverse funzioni interne (private) che in realtà inviavano le funzioni onPause ...

Ad esempio, performStopfunction è la funzione chiamata che a sua volta chiama la funzione onStop:

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;
}

Notare che chiamano onStop dell'attività da qualche parte in questa funzione. Pertanto, potrebbero anche aver inserito tutto il codice (incluso in super.onStop) prima o dopo la chiamata a onStop e quindi notificare alle sottoclassi onStop usando super funzioni vuote onStop e senza nemmeno aggiungere SuperNotCalledException o controllare questa chiamata.

Per questo, se avessero chiamato questo invio ad ActivityLifeCycle in performDestroy invece di chiamarlo alla fine di super.onDestroy, il comportamento della nostra attività sarebbe stato lo stesso indipendentemente da quando abbiamo chiamato il super.

Comunque questa è la prima cosa che fanno (un po 'sbagliata) ed è solo nell'API 14.


La domanda non è mai stata perché la chiamata di super.onDestroy () last abbia senso. Adoro il tuo esempio in biblioteca. Esattamente quello che volevo trasmettere anch'io. Non potrei essere più d'accordo sul chiamare i super metodi per ultimi sui mezzi cicli di distruzione, esattamente come in uno stack; per prevenire la perdita accidentale di dati. Il problema è perché Google insiste nel chiamare prima i super metodi, data la premessa di cui sopra? Ho posto la domanda perché pensavo che forse io, e apparentemente anche tu, forse l'approccio in modo completamente diverso. Saluti
Anudeep Bulla

Oh non ho visto i suggerimenti di Google e l'Altro modo: p! Ascolta, cercherò di creare un'attività che andrà in crash se prima chiami onDestroy. Dovresti provare anche quello. Cheers
Sherif elKhatib

@AnudeepBulla puoi controllare le mie modifiche. E comunque puoi smettere di provare. super.onprobabilmente non interromperà mai la tua attività.
Sherif elKhatib

Wow. Grazie per i suggerimenti. Sia questa che le risposte dell'utente @ forniscono un contesto importante. Se uno di voi può riassumere le risposte in questa pagina, la contrassegnerei come accettata. Si prega di includere: 1. Risposte in questa pagina. 2. Risposta di @ Philip su questa pagina 3. Risposta di @ CommonsWare su questa pagina 4. Questa discussione lo farei, ma non voglio i crediti per le tue meravigliose risposte. Cheers & Thanks
Anudeep Bulla

@AnudeepBulla Sei il benvenuto. Non sono sicuro di come decideremo chi pubblicherà il resoconto finale.
Vikram

2

Dici che Google suggerisce il metodo 1, tuttavia Dianne Hackborn, un noto ingegnere di framework Android suggerisce altrimenti vedi Google Forum Link .

Ha senso intuitivo chiamare la super classe per ultima quando si distrugge un'istanza nei metodi onPause, onStop e onDestroy e prima quando si crea un'istanza con i metodi di onCreate, onResume e onStart .


Il collegamento al post di Dianne Hackborn è importante e conferma lo schema.
Nick Westgate

1

Dal punto di vista di Java, ecco una soluzione per questa confusione:

Perché this () e super () devono essere la prima istruzione in un costruttore?

Il costruttore della classe genitore deve essere chiamato prima del costruttore della sottoclasse. Ciò assicurerà che se chiami qualsiasi metodo sulla classe genitore nel tuo costruttore, la classe genitore sia già stata impostata correttamente.

Quello che stai cercando di fare, passare gli argomenti al super costruttore è perfettamente legale, devi solo costruire quegli argomenti in linea mentre stai facendo, o passarli al tuo costruttore e poi passarli a super:

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

Se il compilatore non lo impone, puoi farlo:

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

Mostra che in realtà i sottocampi devono essere inilializzati prima della supreclasse! Nel frattempo, il requisito java ci "difende" dalla specializzazione della classe specializzando l'argomento del super costruttore

Nei casi in cui una classe genitore ha un costruttore predefinito, la chiamata a super viene inserita automaticamente dal compilatore. Poiché ogni classe in Java eredita da Object, il costruttore di oggetti deve essere chiamato in qualche modo e deve essere eseguito per primo. L'inserimento automatico di super () da parte del compilatore lo consente. Imponendo che super appaia per primo, impone che i corpi del costruttore vengano eseguiti nell'ordine corretto che sarebbe: Object -> Parent -> Child -> ChildOfChild -> SoOnSoForth

(1) Verificare che super sia la prima affermazione non è sufficiente per evitare quel problema. Ad esempio, potresti mettere "super (someMethodInSuper ());" nel tuo costruttore. Questo tenta di accedere a un metodo nella superclasse prima che sia costruito, anche se super è la prima istruzione.

(2) Il compilatore sembra implementare un controllo diverso che è, di per sé, sufficiente a prevenire questo problema. Il messaggio è "impossibile fare riferimento a xxx prima che il costruttore del supertipo sia stato chiamato". Pertanto, verificare che super sia la prima affermazione non è necessario

Si prega di consultare questo http://valjok.blogspot.in/2012/09/super-constructor-must-be-first.html


Capisco perfettamente cosa stai pubblicando. Chiamate prima i costruttori di super classi, perché potrebbero inizializzare le risorse di cui il bambino potrebbe aver bisogno; e i distruttori durano, perché probabilmente non vuoi cancellare tutti i genitori dalle risorse locali, rendendoli inutili. Questo è esattamente il mio punto. E poiché onPause, onStop e onDestroy hanno il compito di salvare le informazioni sullo stato e rendere più o meno disponibili le risorse a GC (quindi in un certo senso distruggerle), li vedo analoghi ai distruttori e quindi penso che chiamarli per ultimi abbia senso. No?
Anudeep Bulla

Tutto ciò che hai detto sopra è esattamente ciò che intendevo quando ho detto "chiamare prima i super metodi ha senso nel mezzo ciclo di creazione". Sono preoccupato e confuso nel caso dei metodi di metà ciclo di distruzione, che sembrano più analoghi ai distruttori. Cheers
Anudeep Bulla

1

La cosa più importante da tenere a mente è che super.onPause()chiama implicitamente setResult(Activity.RESULT_CANCELED). Ma setResultpuò essere chiamato solo una volta e tutte le chiamate successive vengono ignorate. Quindi, se vuoi rimandare qualsiasi tipo di risultato all'attività dei genitori, devi chiamare setResultte stesso, prima di chiamare super.onPause(). Questo è il problema più grande, per quanto ne so.


Wow, questo sembra importante. Quindi c'è una situazione in cui devi assolutamente ritardare la chiamata ai super metodi. Grazie.
Anudeep Bulla

super.onPause() implicitly calls setResult(Activity.RESULT_CANCELED). Potresti dire da dove l'hai preso?
Vikram

Ero confuso. In realtà è finish () che chiama setResult, e super.onBackPressed () chiama finish (). Quindi setResult deve essere sicuramente chiamato prima di super.onBackPressed (). Non sono sicuro che ci siano circostanze in cui super.onPause () potrebbe causare la chiamata di setResult, ma preferisco non rischiare.
Philip Sheard

1

Entrambi sono corretti IMO

Secondo i documenti

Le classi derivate devono chiamare attraverso l'implementazione della super classe di questo metodo. In caso contrario, verrà generata un'eccezione.

Super dovrebbe sempre essere chiamato quando la documentazione lo dice esplicitamente.

Puoi comunque scegliere quando chiamare il super metodo.

Guardando la fonte di onPause

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

Quindi non importa prima o dopo che viene chiamato. Dovresti essere bravo.

Ma per la migliore pratica, dovresti chiamarlo prima.

Lo consiglio principalmente come meccanismo di protezione: se c'è un'eccezione allora il file super metodo dell'istanza sarà già stato chiamato.

Inoltre, mettere queste chiamate sulla prima riga ti aiuterà a evitare di commettere errori in futuro come l'eliminazione del codice nel metodo e l'eliminazione accidentale della chiamata alla super classe.


Mi dispiace se la domanda non è stata del tutto chiara la prima volta, ma dai un'occhiata adesso.
Anudeep Bulla

@AnudeepBulla Questo è quello che ti ho spiegato. Puoi usarli entrambi. Entrambi sono validi.
Sunil Mishra

A quanto mi risulta, l'implementazione personalizzata dei metodi onPause, onStop e onDestroy non è strettamente necessaria. Ho creato molte app senza quelle. Quindi cosa intendi per Super che i metodi dovrebbero sempre essere chiamati? Sono chiamati implicitamente, anche senza sovrascrivere. So anche che funzionano entrambi. Voglio sapere perché i dottori dicono che il super dovrebbe essere chiamato prima. E nel caso in cui la domanda non sia ancora evidente, spiegheresti PERCHÉ, quando dici "Ma per la migliore pratica, dovresti chiamarla prima"?
Anudeep Bulla

Se non esegui l'override, i metodi vengono chiamati da, Base Classma se esegui l'override, è necessario chiamare l' superaltro che avraiandroid.app.SuperNotCalledException
Sunil Mishra,

1
Sembri fraintendere. La domanda non è se chiamare o meno. Come hai sottolineato, DEVI farlo, se li ignori. La domanda è: quando?
Anudeep Bulla

0

Il super dei callback è necessario per mettere l'attività nello stato corretto internamente per il sistema.

Supponiamo che tu avvii la tua attività e onCreate venga richiamato dal sistema. Ora puoi sovrascriverlo e ad esempio caricare il layout. Ma per il flusso del sistema devi chiamare super, che il sistema può continuare con la procedura standard. Ecco perché verrà lanciata un'eccezione se non la chiami.

Ciò avviene indipendentemente dalla tua implementazione in onCreate. È importante solo per il sistema. Se non ci fosse ANR potresti avere un loop infinito in qualsiasi callback e l'attività verrebbe catturata in quello. Quindi, il sistema sa quando la richiamata è stata terminata e quindi chiama quella successiva.

Conosco solo una situazione, in cui è necessario il tempismo della super chiamata. Se vuoi modificare il comportamento standard del tema o del display e simili in onCreate, devi farlo prima di chiamare super per vedere un effetto. Altrimenti, AFAIK non c'è differenza a che ora lo chiami.

Ma per lasciare che il sistema faccia quello che può meglio mettere il super nella prima riga di un callback seguito dal tuo codice, se non hai una buona ragione per romperlo.


La sequenza in onCreate sembra abbastanza comprensibile. Cosa succede nei metodi di distruzione? Dì onStop. Supponiamo che la mia implementazione onStop utilizzi alcune delle risorse che il super metodo rilascia se chiamato, quindi ha senso chiamare il super metodo dopo la mia implementazione.
Anudeep Bulla

Idealmente, dovrebbe essere così, giusto. La nostra attività avrà sempre le risorse di cui dispone la superclasse, e anche di più, e quelle che sono indipendenti dalla mia attività potrebbero, nella maggior parte dei casi, dipendere dalle risorse della superclasse, che sono comuni. Ha più senso occuparsi prima delle mie risorse e poi chiamare la superclasse per occuparsi di quelle comuni. Perché allora Google dice che "DOVREBBE" chiamare prima i metodi della superclasse?
Anudeep Bulla

Di quale risorsa stai parlando, a cui puoi accedere in onCreate ma non in onDestroy?
Steve Benett

Non ho un caso d'uso. Mi chiedo solo come varia con lo stile OOP. I costruttori delle super classi vengono chiamati per primi, prima della tua implementazione, e i distruttori delle super classi vengono chiamati per ultimi, dopo la tua implementazione, giusto? onPause, onStop e onDestroy non sono strettamente distruttori, ma tendono a fare le stesse cose, giusto? Almeno onDestroy e soprattutto onStop .. no?
Anudeep Bulla

Vedi i callback nel modo in cui cambia lo stato non come un costruttore / distruttore. Ogni callback ha la sua necessità, ad esempio creare (pronto per l'uso) / distruggere (la tua ultima possibilità di interagire) un'attività o metterla in primo piano / sfondo. I callback sono lì che puoi controllare le tue risorse nel flusso del sistema. Il sistema controlla solo in quale stato si trova e gestisce di conseguenza. Le risorse che utilizzi e quella controllata dal sistema sono indipendenti l'una dall'altra e non ci saranno intersezioni.
Steve Benett
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.