Нет необходимости приводить результат findViewById?

152

Недавно я обнаружил, что AndroidStudio напоминает мне удалить некоторые классы. Я помню, что в старые времена нам приходилось приводить результат findViewById, но теперь это не обязательно.

Результат findViewById по-прежнему View, поэтому я хочу знать, почему нам не нужно приводить класс?

Я не могу найти никаких документов, упомянутых, кто-нибудь может найти какой-либо документ?

Эрик Чжао
источник
7
потому что сейчас это <T extends View> T findViewById(int id)?
Селвин
вам нужно выполнить приведение в случае какой-либо операции, которой нет в классе View, как, например, в случае ImageView. Если вы хотите использовать setImageResource, то вам нужно привести приведение findViewById к ImageView
Gagan Deep
Но я чувствую себя немного неудобно, чтобы сразу узнать тип переменной, если убрал «лишнее» приведение.
Fruit

Ответы:

236

Начиная с API 26, findViewByIdиспользует логический вывод для своего типа возвращаемого значения, поэтому вам больше не нужно приводить.

Старое определение:

View findViewById(int id)

Новое определение:

<T extends View> T findViewById(int id)

Так что если вам compileSdkпо крайней мере 26, это означает, что вы можете использовать это :)

Эдуард Б.
источник
Спасибо и еще один вопрос. Я не могу найти источники для SDK26 в SDK Manager, так где я могу найти это новое определение, пожалуйста?
Эрик Чжао
17
Если мы удалим приведение, наши приложения могут все еще работать на более низких устройствах, правильно?
user1032613
17
@ user1032613: Да, приложения могут работать на более низких устройствах без каких-либо проблем.
Алиреза Нурали,
1
Будет ли это исключение, если это неправильный тип?
fobbymaster
1
Как в случае, если представление в файле макета имеет другой тип? Да, конечно, это все равно будет ClassCastException.
Эдуард Б.
13

Согласно этой статье :

Следующая функция опирается на общий вывод типов в Java, чтобы исключить необходимость приведения вручную:

protected <T extends View> T findViewById(@IdRes int id) {
    return (T) getRootView().findViewById(id);
}
zeroDivider
источник
11

В старых версиях:

AutoCompleteTextView name = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);

Из Android Studio 3.0 с SDK 26:

AutoCompleteTextView name = findViewById(R.id.autoCompleteTextView);
Midhun
источник
16
Это не дает ответа на вопрос.
Виджай Шарма
1

Android Studio напоминает об удалении приведения, если вы используете общие атрибуты из класса View , например, видимость или некоторые распространенные методы, такие как onClick ().

Например:

((ImageView) findViewById(R.id.image_car)).setVisibility(View.VISIBLE);

В этом случае вы можете просто написать:

findViewById(R.id.image_car).setVisibility(View.VISIBLE);
Тим
источник
2
вам все еще нужно объявить тип, вам нужно написать: findViewById <ImageView> (R.id.image_car) .setVisibility (View.VISIBLE);
Slickelito
Android Studio напоминает нам об удалении явного приведения, потому что он изменился при реализации автоматического вывода типов в Java - он не имеет никакого отношения к тому, какой метод вы используете.
zeroDivider
1

Android 0, очистить кастинг

Одна из вещей, которую google объявляет в IO 2017, называется «выбрасывать» :). Разработчик Android не должен выполнять кастинг вручную для findViewById (). Например, старый способ получить текстовое представление с помощью findViewById () будет выглядеть примерно так.

TextView txtDesc = (TextView) findViewById(R.id.textViewDesc);
txtDesc.setText(getString(R.string.info_angkot_description));

Пока новый путь будет таким

TextView txtDesc = findViewById(R.id.textViewDesc);
txtDesc.setText(getString(R.string.info_angkot_description));

Это простое изменение. Но для опытного программиста чистый код, подобный этому, может сделать вас очень счастливым, и это поможет вам настроиться программировать :)

Чтобы сделать это, вам нужно было только установить версию скомпилированного SDK вашего проекта на версию 26 в вашем build.gradle приложения.

Вы все еще можете использовать более раннюю версию SDK, так что это ненавязчивые изменения.

Теперь реальная проблема, как вы чистите тот старый код, который использует приведение все это время. Особенно, когда у вас есть как сотни файлов деятельности. Вы можете сделать это вручную, или, возможно, нанять стажера, чтобы сделать это 😛. Но, к счастью для всех этих интернов, андроид студия уже готова помочь нам в этом.

Когда вы кладете свою карету (или нажимаете на избыточное приведение), студия андроида предложит 2 варианта обработки избыточного преобразования.

Сначала будет предложено удалить это избыточное приведение, или вы можете выбрать очистить код. Это удалит все лишние преобразования для этого файла. Это лучше, но мы хотим большего. Мы не хотим открывать каждый файл и очищать его один за другим.

Особенностью идеи IntelliJ является то, что эта функция называется намеренным действием. Все, что вам нужно сделать, это нажать Ctrl + Shift + A, а затем набрать clean. Выберите действие «Очистка кода» и выделите весь объем проекта. С помощью этих нескольких простых шагов ваш код станет намного чище.

Одним из важных моментов является то, что вы делаете это с некоторой системой управления версиями кода. Таким образом, вы можете сравнить изменения, внесенные действием намерения, и отменить любые файлы, которые вы хотите.

Скопировано из оригинального поста:

https://medium.com/@abangkis/android-0-clean-up-casting-c30acec56cef

daliaessam
источник
1
вопрос был why, а не how:The result of findViewById is still View, so i want to know why we don't need to cast the class?
zeroDivider
Msgstr "Все, что вам нужно сделать, это нажать Ctrl + Shift + A, а затем набрать" clean ". Что ты имеешь в виду под «чистым типом»? Если вы начнете печатать в этот момент, вы сотрете весь файл
Stealth Rabbi
0

В исходном коде ViewGroupесть приведение аргумента возврата. Так что нет необходимости снова разыгрывать:

@Nullable
public final <T extends View> T findViewById(@IdRes int id) {
    if (id == NO_ID) {
        return null;
    }
    return findViewTraversal(id);
}

@Override
protected <T extends View> T findViewTraversal(@IdRes int id) {
    if (id == mID) {
        return (T) this;  //###### cast to T
    }

    final View[] where = mChildren;
    final int len = mChildrenCount;

    for (int i = 0; i < len; i++) {
        View v = where[i];

        if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
            v = v.findViewById(id);

            if (v != null) {
                return (T) v; //###### cast to T
            }
        }
    }

    return null;
}
деятельность
источник