2012-02-08 17 views
10

Al crear una vista personalizada, he notado que muchas personas parecen hacerlo de esta manera:¿Debo llamar a super() o llamar a this() para los constructores de vista personalizada de Android?

public MyView(Context context) { 
    super(context); 
    // this constructor used when programmatically creating view 
    doAdditionalConstructorWork(); 
} 

public MyView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    // this constructor used when creating view through XML 
    doAdditionalConstructorWork(); 
} 

private void doAdditionalConstructorWork() { 
    // init variables etc. 
} 

Mi problema con esto es que me impide hacer mi variables final. ¿Alguna razón para no hacer lo siguiente?

public MyView(Context context) { 
    this(context, null); 
    // this constructor used when programmatically creating view 
} 

public MyView(Context context, AttributeSet attrs) { 
    this(context, attrs, 0); 
    // this constructor used when creating view through XML 
} 

public MyView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    // this constructor used where? 
    // init variables 
} 

he sido capaz de crear la vista muy bien a través de XML y por medio de código, pero no estoy seguro de si hay alguna desventaja de este enfoque. ¿Funcionará esto en todos los casos?

Hay another part to this question

+0

Llamar 'this' solo invoca a otro constructor de la clase actual. Creo que esto es algo de lo que no te habías dado cuenta. Así 'this (context, null);' llama 'public MyView (Context context, AttributeSet attrs) {' que a su vez llama 'public MyView (Context context, AttributeSet attrs, int defStyle) {'. Las invocaciones de este constructor no son muy comunes en el lenguaje Java, pero no veo ninguna razón para que esto no funcione. –

+0

Me di cuenta de que solo me preocupaban los parámetros. :) –

Respuesta

-5

Está bien.

Cuando miramos la fuente de TextView.java.

Han utilizado la misma jerarquía.

Así que está de acuerdo con este enfoque.

+0

Las personas abajo votando esto, mencione la razón también. También he agregado la referencia de implementación de Android. Esta respuesta es correcta con el escenario dado de OP. –

-2

Sí, eso es un patrón razonable utilizar por lo que no hace tener que repetir el trabajo de encargo en cada uno de sus constructores. Y no, no parece haber ningún inconveniente en el método.

-2

Es puramente depende de su requisito. Digamos que si quieres usar cualquier método en la clase principal sin anular su funcionalidad en tu vista personalizada, entonces necesitas usar super() y crear una instancia de la clase padre. Si no necesita invocar ningún método en la clase principal, todas las implementaciones se anulan en su vista personalizada, entonces no es necesario. Lea Un ejemplo de vista personalizado sección en este link.

7

El único inconveniente que puedo ver (que nadie parece haber mencionado) es que su segundo constructor pierde el defStyle de la superclase, porque lo establece en cero. Mire el código fuente de cualquiera de las clases de Vista de Android, y notará que el segundo constructor siempre tiene un defStyle específico definido.

Por ejemplo, este es el segundo constructor de ListView:

public ListView(Context context, AttributeSet attrs) { 
    this(context, attrs, com.android.internal.R.attr.listViewStyle); 
} 

Si se va a extender ListView usando el segundo enfoque que usted describe, com.android.internal.R.attr.listViewStyle ya no sería el defStyle, ya que estaría pasando por alto ese segundo super constructor y lo convierte en cero en su lugar. Supongo que se podría resolver esto mediante el uso de la misma como defstyle ListView, así:

public MyView(Context context, AttributeSet attrs) { 
    this(context, attrs, android.R.attr.listViewStyle); 
} 

pero no es exactamente la forma "purista", ya que está forzando artificialmente a tener el mismo defStyle como ListView.

Por lo tanto, al contrario de lo que dijeron los demás, creo que es mejor usar el primer enfoque doAdditionalConstructorWork() descrito en su publicación, porque al menos se asegura de que el defStyle esté configurado correctamente.

+0

pero mirando el código fuente 'View' podemos ver que ** establece **' defStyle' en 0: 'public View (Context context, AttributeSet attrs) { this (context, attrs, 0); } ' –

3

Copié esto de mi respuesta para una pregunta similar.

Si anula los tres constructores, NO CASCADE this(...) LLAMADAS. En su lugar, debería estar haciendo esto:

public MyView(Context context) { 
    super(context); 
    init(context, null, 0); 
} 

public MyView(Context context, AttributeSet attrs) { 
    super(context,attrs); 
    init(context, attrs, 0); 
} 

public MyView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    init(context, attrs, defStyle); 
} 

private void init(Context context, AttributeSet attrs, int defStyle) { 
    // do additional work 
} 

La razón es que la clase padre podría incluir atributos predeterminados en sus propios constructores que usted puede ser accidental anular. Por ejemplo, este es el constructor para TextView:

public TextView(Context context) { 
    this(context, null); 
} 

public TextView(Context context, @Nullable AttributeSet attrs) { 
    this(context, attrs, com.android.internal.R.attr.textViewStyle); 
} 

public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 
    this(context, attrs, defStyleAttr, 0); 
} 

Si no llama super(context), que no tendría que configurar correctamente R.attr.textViewStyle como el attr estilo.

Cuestiones relacionadas