2010-11-18 10 views
60

Me preguntaba, al crear nuevas clases Activity y luego anulando el método onCreate(), en Eclipse siempre me agrego automáticamente: super.onCreate(). ¿Como sucedió esto? ¿Existe una palabra clave java en el resumen o clase principal que lo fuerza?¿Cómo forzar a la clase derivada a llamar al supermétodo? (Como Android lo hace)

No sé si es ilegal no llamar a la súper clase, pero recuerdo que en algunos métodos obtuve una excepción por no hacer esto. ¿Esto también está incorporado en Java? ¿Puedes usar alguna palabra clave para hacer eso? ¿O cómo se hace?

+0

Quiero saber esto también. Y no solo es útil Eclipse, si elimino la llamada a super.onCreate(), la aplicación genera un error de tiempo de ejecución que dice: "no llamó a super.onCreate()". Así que sí, realmente te obliga a llamar al súper método. ¿Pero cómo? –

+0

@RodrigoCastro Puede revisar los javadocs para cada método. Por ejemplo [onCreate()] (http://developer.android.com/reference/android/app/Activity.html#onCreate (android.os.Bundle)). –

Respuesta

9

Aquí está la fuente de Activity#onCreate() - es casi todos los comentarios (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; 
} 

así, creo que ha de ser que el ADT plugin Eclipse es lo que es auto-adición de esa llamada a super.onCreate() para usted. Sin embargo, es una suposición total.

+0

Supongo que el 'mCalled = true' también se usa para una posible excepción. Tal vez no en 'onCreate()', pero cuando se lanza una excepción, usará ese patrón simple. – Peterdk

3

No hay nada en Java que fuerce la invocación de super, y hay muchos ejemplos cuando no lo desea. El único lugar donde puedes forzar la llamada de super es en constructores. Todos los constructores tienen que llamar a un constructor de superclase. Uno (el constructor sin argumentos) se insertará si no escribe uno explícitamente, y si no hay un constructor sin argumentos, debe llamarlo explícitamente.

3

Eclipse es útil, y le recuerda que puede llamar a la implementación de la superclase si lo desea.

probablemente esté recibiendo un error porque no está haciendo algo necesario que la superclase, ya que no está llamando a su implementación.

7

Si quiere estar absolutamente seguro de que también se llama al método de superclase, debe engañar un poco: no permita que se sobrescriba el método de superclase, pero haga que llame a un método protegido invalidable.

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

De esta manera, el usuario debe llamar Super.foo() o Base.foo() y siempre será la versión de la clase base, ya que fue declarado como final. El material específico de la implementación se encuentra en impl_stuff(), que puede anularse.

71

Si desea fuerza subclases para ejecutar la lógica de la clase padre, un patrón común es algo como lo siguiente:

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

Esta realidad no responde a su pregunta acerca de lo que incita a Eclipse automáticamente insertar una llamada de superclase en la implementación; pero no creo que ese sea el camino a seguir, ya que esto siempre se puede eliminar.

No se puede exigir que un método debe llamar a la versión de la superclase con una palabra clave Java, o algo por el estilo. Sospecho que tus excepciones simplemente provienen de algún código en la clase padre que verifica invariantes esperados, o algo, que fueron invalidados por tu enfoque. Tenga en cuenta que esto es sutilmente diferente de lanzar una excepción porque no pudo llamar al super.onCreate().

8

Para responder a su pregunta real, la creación automática de la llamada a super.onCreate() es una característica del complemento ADT. En java, no se puede forzar directamente a una subclase para que invoque la implementación súper de un método, afaik (consulte el patrón descrito en otras respuestas para solucionar problemas). Sin embargo, ten en cuenta que en Android no estás instanciando objetos de actividad (u objetos de servicio) directamente: pasas una intención al sistema y el sistema crea una instancia del objeto y llama a Crear() sobre él (junto con otros métodos de ciclo de vida). Entonces, el sistema tiene una referencia de objeto directo a la instancia de la Actividad y es capaz de verificar (presumiblemente) algún Booleano que se establece en verdadero en la implementación de la superclase de onCreate(). Aunque no sé exactamente cómo se implementa, es probable que se ve algo como esto:

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

Y en el "sistema" clase nivel que recibe la intención y una instancia del objeto Actividad de ella:

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

Supongo que es probablemente un poco más complejo que eso, pero ya entiendes la idea. Eclipse crea automáticamente la llamada porque el complemento ADT se lo dice, para su comodidad. Feliz codificación!

134

Esto se añade en la biblioteca de soporte de anotaciones:

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

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

@CallSuper

+0

Sí, golpeaste el clavo en la cabeza aquí. Gracias. –

+0

No probado aún, pero lea la documentación. Esto va a ser increíble, supongo. Esta debería ser la respuesta aceptada. –

+0

Lo siento pero necesito cambiar mi comentario. No forzó a implementar el supermétodo. Pude ejecutar la aplicación sin cenar. –

Cuestiones relacionadas