Должен ли я вызвать super() или this() для конструкторов пользовательских представлений 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.
}
Моя проблема в том, что это мешает мне сделать окончательные переменные. Есть ли причина не делать следующее?
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 и кода, но я не уверен, есть ли какие-либо недостатки этого подхода. Будет ли это работать во всех случаях?
Есть еще одна часть этого вопроса
5 ответов
Редактировать:
Это не хорошо. Смотрите другие ответы на этот вопрос по причинам.
Оригинальный ответ:
Все в порядке.
Когда мы смотрим на источник TextView.java
,
Они использовали одну и ту же иерархию. Так что с этим подходом у вас все в порядке.
Единственный недостаток, который я вижу (который, кажется, никто не упомянул), это то, что ваш второй конструктор теряет defStyle
суперкласса, потому что вы устанавливаете его на ноль. Посмотрите на исходный код любого из классов View 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
потому что вы будете обходить этот второй супер-конструктор и делать его нулевым. Я полагаю, вы могли бы решить эту проблему, используя тот же defstyle
как ListView, вот так:
public MyView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.listViewStyle);
}
Но это не совсем "пуристский" способ, потому что вы искусственно заставляете его иметь то же самое defStyle
как ListView.
Так что, вопреки тому, что сказали другие, я на самом деле думаю, что вам лучше использовать первый 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
как стиль
Да, это разумный шаблон для использования, поэтому вам не нужно повторять пользовательскую работу в каждом из ваших конструкторов. И нет, у этого метода нет недостатков.
Это чисто зависит от вашего требования. Допустим, если вы хотите использовать какие-либо методы в родительском классе, не переопределяя их функциональность в пользовательском представлении, вам нужно использовать super() и создать экземпляр родительского класса. Если вам не нужно вызывать какие-либо методы в родительском классе, все реализации переопределяются в вашем пользовательском представлении, тогда вам это не нужно. Прочитайте раздел " Пользовательский пример просмотра " по этой ссылке.