Ответ 1
Это нормально.
Когда мы посмотрим на источник TextView.java
.
Они использовали одну и ту же иерархию.
Итак, вы с этим согласны.
При создании пользовательского представления я заметил, что многие люди делают это следующим образом:
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 и через код, но я не уверен, есть ли какие-то недостатки в этом подходе. Будет ли это работать во всех случаях?
Есть другая часть этого вопроса
Это нормально.
Когда мы посмотрим на источник TextView.java
.
Они использовали одну и ту же иерархию.
Итак, вы с этим согласны.
Единственный недостаток, который я вижу (что никто, кажется, не упоминал), заключается в том, что ваш второй конструктор теряет defStyle
суперкласса, потому что вы устанавливаете его на ноль. Посмотрите исходный код для любого из классов Android View, и вы заметите, что второй конструктор всегда имеет определенный 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
.
Скопировал это из моего ответа по аналогичному вопросу.
Если вы переопределите все три конструктора, не используйте CASCADE this(...)
CALLS. Вы должны сделать это:
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.
Да, это разумный шаблон для использования, поэтому вам не нужно повторять пользовательскую работу в каждом из ваших конструкторов. И нет, не существует никаких недостатков метода.
Это зависит от вашего требования. Скажем, если вы хотите использовать любые методы в родительском классе, не переопределяя их функциональность в своем пользовательском представлении, вам нужно использовать super() и создать экземпляр родительского класса. Если вам не нужно ссылаться на какие-либо методы в родительском классе, все реализации переопределяются в вашем пользовательском представлении, тогда вам не нужно. В разделе прочитайте Пример пользовательского вида.