对于android自定义视图构造函数,我应该调用super()还是调用this()?

对于android自定义视图构造函数,我应该调用super()还是调用this()?,android,android-custom-view,Android,Android Custom View,创建自定义视图时,我注意到许多人似乎是这样做的: public MyView(Context context) { super(context); // this constructor used when programmatically creating view doAdditionalConstructorWork(); } public MyView(Context context, AttributeSet attrs) { super(context, attrs

创建自定义视图时,我注意到许多人似乎是这样做的:

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.
}
我的问题是,它阻止我将变量设置为最终变量。有没有理由不做以下事情

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
}
我已经能够通过XML和代码很好地创建视图,但我不确定这种方法是否有任何缺点。这在所有情况下都有效吗


是的,这是一种合理的使用模式,因此您不必在每个构造函数中重复自定义工作。不,该方法似乎没有任何缺点。

编辑: 这不好。有关原因,请参阅此问题的其他答案


原始答复: 没关系

当我们看到这个问题的根源时

他们使用了相同的层次结构。
所以您可以接受这种方法。

这完全取决于您的需求。让我们假设,如果您想在不重写自定义视图中的功能的情况下使用父类中的任何方法,那么您需要使用super()并实例化父类。若您不需要调用父类中的任何方法,那个么所有的实现都会在您的自定义视图中被重写,那个么您就不需要。阅读本节中的自定义视图示例。

我能看到的唯一缺点(似乎没有人提到)是,您的第二个构造函数丢失了超类的
defStyle
,因为您将其设置为零。查看任何Android视图类的源代码,您会注意到第二个构造函数总是定义了一个特定的
defStyle

例如,这是ListView的第二个构造函数:

public ListView(Context context, AttributeSet attrs) {
    this(context, attrs, com.android.internal.R.attr.listViewStyle);
}
如果要使用您描述的第二种方法扩展ListView,
com.android.internal.R.attr.listViewStyle
将不再是
defStyle
,因为您将绕过第二个超级构造函数,而将其设为零。我想您可以通过使用与ListView相同的
defstyle
来解决这个问题,如下所示:

public MyView(Context context, AttributeSet attrs) {
    this(context, attrs, android.R.attr.listViewStyle);
}
但这并不完全是“纯粹”的方式,因为您人为地强迫它使用与ListView相同的
defStyle


因此,与其他人所说的相反,我实际上认为您最好使用本文中概述的第一种
doAdditionalConstructorWork()
方法,因为这至少可以确保
defStyle
设置正确。

从我对类似问题的回答中复制了这一点

如果覆盖所有三个构造函数,请不要级联
this(…)
调用。您应该这样做:

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
}
原因是父类可能在其自己的构造函数中包含默认属性,您可能会意外地重写这些属性。例如,这是
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);
}

如果您没有调用
super(context)
,您就不会正确地将
R.attr.textViewStyle
设置为样式attr。

调用
this
只会调用当前类的另一个构造函数。我想这是你没有意识到的。因此
this(上下文,null)调用公共MyView(上下文上下文,属性集属性){
然后调用公共MyView(上下文上下文,属性集属性,int-defStyle){。这种构造函数调用在java语言中并不常见,但我看不出有什么理由不起作用。我意识到,我只是关心参数。:)但查看
视图
源代码,我们可以看到它将
defStyle
设置为0:
公共视图(上下文上下文,AttributeSet attrs){this(context,attrs,0);}
人们对此投了反对票,请同时说明原因。我也添加了android自己的实现参考。这个答案在OP的给定场景中是正确的。你可能因为其他答案中显而易见的原因而被否决,比如:谢谢@VickyChijwani,我明白了。