2010-11-18 27 views
60

Mi stavo chiedendo, quando ho creato nuove classi Activity e poi ho annullato il metodo onCreate(), in eclissi mi viene sempre aggiunto automaticamente: super.onCreate(). Come succede? Esiste una parola chiave java nella classe astratta o genitore che forza questo?Come forzare la classe derivata a chiamare il super metodo? (Come Android fa)

Non so se è illegale non chiamare la super classe, ma ricordo in alcuni metodi che ho ottenuto un'eccezione lanciata per non farlo. Questo è anche incorporato in java? Puoi usare qualche parola chiave per farlo? O come è fatto?

+0

Voglio sapere questo. E non è solo Eclipse utile, se rimuovo la chiamata a super.onCreate(), l'app fornisce un errore di runtime che dice: "non ha chiamato super.onCreate()". Quindi sì, ti sta davvero costringendo a chiamare il metodo super. Ma come? –

+0

@RodrigoCastro È possibile rivedere i javadoc per ciascun metodo. Ad esempio [onCreate()] (http://developer.android.com/reference/android/app/Activity.html#onCreate (android.os.Bundle)). –

risposta

9

Ecco la fonte di Activity#onCreate() - è quasi tutti i commenti (original - see line ~800):

/** 
* Called when the activity is starting. This is where most initialization 
* should go: calling {@link #setContentView(int)} to inflate the 
* activity's UI, using {@link #findViewById} to programmatically interact 
* with widgets in the UI, calling 
* {@link #managedQuery(android.net.Uri , String[], String, String[], String)} to retrieve 
* cursors for data being displayed, etc. 
* 
* <p>You can call {@link #finish} from within this function, in 
* which case onDestroy() will be immediately called without any of the rest 
* of the activity lifecycle ({@link #onStart}, {@link #onResume}, 
* {@link #onPause}, etc) executing. 
* 
* <p><em>Derived classes must call through to the super class's 
* implementation of this method. If they do not, an exception will be 
* thrown.</em></p> 
* 
* @param savedInstanceState If the activity is being re-initialized after 
*  previously being shut down then this Bundle contains the data it most 
*  recently supplied in {@link #onSaveInstanceState}. <b><i>Note: Otherwise it is null.</i></b> 
* 
* @see #onStart 
* @see #onSaveInstanceState 
* @see #onRestoreInstanceState 
* @see #onPostCreate 
*/ 
protected void onCreate(Bundle savedInstanceState) { 
    mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
      com.android.internal.R.styleable.Window_windowNoDisplay, false); 
    mCalled = true; 
} 

così, la mia ipotesi sarebbe che il plugin ADT Eclipse è ciò che è auto-aggiungendo che chiamata a super.onCreate() per voi. È un'ipotesi totale, però.

+0

Suppongo che 'mCalled = true' sia usato anche per una possibile eccezione. Forse non nel 'onCreate()' ma quando effettivamente viene lanciata un'eccezione userà questo schema semplice. – Peterdk

3

Non c'è nulla in Java che costringa a chiamare super e ci sono molti esempi in cui non si vorrebbe. L'unico posto dove puoi forzare la chiamata di super è nei costruttori. Tutti i costruttori devono chiamare un costruttore di superclasse. Uno (il costruttore senza argomenti) verrà inserito se non ne scrivi uno esplicitamente, e se non esiste un costruttore no-arguments, devi chiamarlo esplicitamente.

3

Eclipse è solo utile, ricordandoti che puoi chiamare l'implementazione della superclasse se vuoi.

probabilmente stai ricevendo un errore perché non stai facendo qualcosa di necessario per la superclasse, dal momento che non stai chiamando la sua implementazione.

7

Se si vuole assolutamente essere sicuri che venga chiamato anche il metodo della superclasse, è necessario ingannare un po ': non consentire la sovrascrittura del metodo della superclasse, ma chiamare un metodo protetto sovrascrivibile.

class Super 
{ 
    public final void foo() { 
     foo_stuff(); 
     impl_stuff(); 
    } 

    protected void impl_stuff() { 
     some_stuff_that_you_can_override(); 
    } 
} 

class Base extends Super 
{ 
    protected void impl_stuff() { 
    my_own_idea_of_impl(); 
    } 
} 

In questo modo, l'utente deve chiamare Super.foo() o Base.foo() e sarà sempre la versione della classe base come è stato dichiarato come finale. Le cose specifiche dell'implementazione sono in impl_stuff(), che può essere sovrascritto.

71

Se si vuole forza sottoclassi per eseguire la logica classe genitore, un modello comune è qualcosa di simile al seguente:

public abstract class SuperClass implements SomeInterface 
{ 
    // This is the implementation of the interface method 
    // Note it's final so it can't be overridden 
    public final Object onCreate() 
    { 
     // Hence any logic right here always gets run 
     // INSERT LOGIC 

     return doOnCreate(); 

     // If you wanted you could instead create a reference to the 
     // object returned from the subclass, and then do some 
     // post-processing logic here 
    } 

    protected abstract Object doOnCreate(); 
} 

public class Concrete extends SuperClass 
{ 
    @Override 
    protected Object doOnCreate() 
    { 
     // Here's where the concrete class gets to actually do 
     // its onCreate() logic, but it can't stop the parent 
     // class' bit from running first 

     return "Hi"; 
    } 
} 

Questo in realtà non risponde alla tua domanda su cosa spinge Eclipse per automaticamente inserire una chiamata di superclasse nell'implementazione; ma poi non penso che sia il modo di andare comunque dato che questo può sempre essere cancellato.

In realtà non è possibile imporre che un metodo debba chiamare la versione della superclasse con una parola chiave Java o qualcosa di simile. Sospetto che le tue eccezioni derivino semplicemente da un codice nella classe genitore che controlla le invarianti previste, o qualcosa che è stato invalidato dal tuo approccio. Si noti che questo è leggermente diverso dal lancio di un'eccezione perché non è possibile chiamaresuper.onCreate().

8

Per rispondere alla tua domanda, l'auto-creazione della chiamata a super.onCreate() è una funzionalità del plugin ADT. In java, non è possibile forzare direttamente una sottoclasse a chiamare la super implementazione di un metodo, afaik (vedere lo schema descritto in altre risposte per aggirare il problema). Tuttavia, tieni presente che in Android non stai istanziando direttamente oggetti Attività (o oggetti Servizio): passi un Intento al sistema e il sistema crea un'istanza dell'oggetto e chiama suCreate() su di esso (insieme ad altri metodi del ciclo di vita). Quindi il sistema ha un riferimento diretto all'istanza Activity ed è in grado di controllare (presumibilmente) un booleano impostato su true nell'implementazione della superclasse di onCreate(). Anche se non so esattamente come viene implementato, probabilmente sembra qualcosa di simile:

class Activity 
{ 
    onCreate() 
    { 
    superCalled = true; 
    ... 
    } 
    ... 
} 

E nel "sistema" classe di livello che riceve l'intento e un'istanza dell'oggetto di attività da esso:

... 
SomeActivitySubclass someActivitySubclassObject = new SomeActivitySubclass(); 
someActivitySubclassObject.onCreate(); 
if (!someActivityObject.isSuperCalled()) 
{ 
    Exception e = new Exception(...) //create an exception with appropriate details 
    throw e; 
} 

La mia ipotesi è che probabilmente è leggermente più complessa di così, ma si ottiene l'idea. Eclipse crea automaticamente la chiamata perché il plug-in ADT lo dice, per comodità. Buona programmazione!

134

questo si aggiunge nella libreria di supporto di annotazione:

dependencies { 
    compile 'com.android.support:support-annotations:22.2.0' 
} 

http://tools.android.com/tech-docs/support-annotations

@CallSuper

+0

Sì, hai colpito l'unghia sulla testa qui. Grazie. –

+0

Non ancora provato ma leggi la documentazione. Sarà fantastico, immagino. Questa dovrebbe essere la risposta accettata. –

+0

Scusate ma ho bisogno di cambiare il mio commento. Non è stato costretto ad implementare il super metodo. Sono stato in grado di eseguire l'app senza la chiamata a cena. –

Problemi correlati