Я более подробно остановлюсь на ответе Андреаса, предназначенном для этого конкретного набора классов.
EditText
- это подкласс TextView
.Вот почему он объявлен как:
class EditText extends TextView
(Упрощенный ...)
Конструкторы EditText выглядят так:
public EditText(Context context) {
this(context, null);
}
public EditText(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.editTextStyle);
}
public EditText(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public EditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
Обратите внимание, как каждый конструктор вызывает другой допоследний (длинный).Это сложно, потому что он вызывает super(…)
, то есть теперь он вызывает конструктор суперкласса (TextView
).
EditText - это просто специализированный TextView, как мы можем из этого сделать вывод;TextView также объявляет переменную с именем text
, которую, конечно, также использует EditText.Когда вы запрашиваете EditText для text
, он просто использует код, который уже есть у TextView и который вы обнаружили:
@Override
public Editable getText() {
CharSequence text = super.getText();
// This can only happen during construction.
if (text == null) {
return null;
}
[rest of code removed for clarity]
}
Поэтому он запрашивает у super
(TextView) text
;почему этот текст может быть нулевым?Чтобы ответить на этот вопрос, вам нужно взглянуть на саму TextView
(https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/TextView.java).
около 1000 строк кода позже ... TextView объявляет свои конструкторы; я вставлю один для простоты, но они очень просты:
public TextView(Context context) {
this(context, null);
}
Обратите внимание, что они снова вызывают this(…)
и цепочку конструкцию ... один конструктор вызывает другой и так далее ... до последнего большого для TextViewдостигается ...
@SuppressWarnings("deprecation")
public TextView(
Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
// TextView is important by default, unless app developer overrode attribute.
if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) {
setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES);
}
setTextInternal("");
[rest of code removed for clarity]
Обратите внимание, что этот конструктор вызывает setTextInternal("")
, что выглядит подозрительно! Он устанавливает текст как пустую строку при построении, так что это будет невозможно для TextView
иметь нулевой текст после завершения работы этого конструктора ( вы можете использовать отражение ... но давайте не будем идти туда ), поскольку конструкторы EditText
объединены в цепочку и заканчиваются всегда вызывая конструкторы TextView
, этот метод setTextInternal("")
является гарантированно вызываемым в какой-то момент во время конструирования объекта в Java (вот что такое Конструкторы и это Javaконтракт, который разрушил бы половину мира, если бы он был ненадежным!).
Что делает этот метод?
Очевидно, куча внутренних вещей, среди прочего ...
// Update mText and mPrecomputed
private void setTextInternal(@Nullable CharSequence text) {
mText = text; // #### THIS IS WHERE IT SETS THE TEXT TO NON NULL ("").
mSpannable = (text instanceof Spannable) ? (Spannable) text : null;
mPrecomputed = (text instanceof PrecomputedText) ? (PrecomputedText) text : null;
}
Если вы помните, что EditText#getText()
называется super.getText()
Угадайте, как это выглядит в супер?(TextView
):
public CharSequence getText() {
return mText;
}
Правильно, та же самая ссылка / экземпляр mText
, которую setTextInternal()
изменили во время конструирования TextView.
Вот почему во время построения (и до вызова setTextInternal("")
, поле mText
(доступ к которому осуществляется через getText()
) может быть нулевым, но не после.
¯\_(ツ)_/¯
Честно говоря, я даже не знаю, почему они это делают, и комментарий кажется довольно глупым, но, как вы, наверное, уже догадались, эти классы представляют собой тысячи строккод, и каждый склонен полагать, что должна существовать причина для его существования; лучшее, что вы можете сделать, это начать анализировать весь класс TextView. Удачи с этим.:)