我应该调用super()还是为Android自定义视图构造函数调用this()?

Mic*_*ine 12 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);
  // this constructor used when creating view through XML
  doAdditionalConstructorWork();
}

private void doAdditionalConstructorWork() {
  // init variables etc.
}
Run Code Online (Sandbox Code Playgroud)

我的问题在于它阻止我使我的变量最终.有什么理由不做以下事情?

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
}
Run Code Online (Sandbox Code Playgroud)

我已经能够通过XML和代码创建视图,但我不确定这种方法是否有任何缺点.这会在所有情况下都有效吗?

这个问题还有另外一部分

Xåp*_* - 8

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

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

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

如果您使用您描述的第二种方法扩展ListView,则com.android.internal.R.attr.listViewStyle不再是defStyle,因为您将绕过第二个超级构造函数并将其设置为零.我想你可以使用与defstyleListView 相同的方法解决这个问题,如下所示:

public MyView(Context context, AttributeSet attrs) {
    this(context, attrs, android.R.attr.listViewStyle);
}
Run Code Online (Sandbox Code Playgroud)

但它并不完全是"纯粹主义"的方式,因为你人为地强迫它与defStyleListView 相同.

所以,与其他人所说的相反,我实际上认为你最好使用doAdditionalConstructorWork()帖子中列出的第一种方法,因为这至少可以确保defStyle设置正确.


Jin*_*Jin 5

从我的回答中复制了一个类似的问题。

如果覆盖所有三个构造函数,请不要进行级联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
}
Run Code Online (Sandbox Code Playgroud)

原因是父类可能在其自己的构造函数中包含默认属性,您可能会意外覆盖它们。例如,这是用于的构造函数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);
}
Run Code Online (Sandbox Code Playgroud)

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


Adi*_*mro -6

编辑:

这不行。查看此问题的其他答案以了解原因。


原答案:

没关系。

当我们查看 的来源时TextView.java

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