Nie ma potrzeby rzutowania wyniku findViewById?

152

Niedawno odkryłem, że AndroidStudio przypomina mi o usunięciu niektórych rzutów klas. Pamiętam, że w dawnych czasach musieliśmy rzutować wynik findViewById, ale teraz nie jest to konieczne.

Wynikiem findViewById nadal jest View, więc chcę wiedzieć, dlaczego nie musimy rzutować klasy?

Nie mogę znaleźć żadnych wymienionych dokumentów, czy ktoś może znaleźć jakiś dokument?

Eric Zhao
źródło
7
ponieważ teraz jest <T extends View> T findViewById(int id)?
Selvin,
potrzebujesz rzutowania w przypadku jakiejkolwiek operacji, której nie ma w klasie View, jak w przypadku ImageView, Jeśli chcesz użyć setImageResource, musisz rzucić findViewById za pomocą ImageView
Gagan Deep
Ale czuję się trochę niewygodnie, aby poznać typ zmiennej na pierwszy rzut oka, jeśli usunięto „redundantne” rzutowanie.
Owoce

Odpowiedzi:

235

Począwszy od API 26, findViewByIdużywa wnioskowania dla swojego typu zwracanego, więc nie musisz już rzutować.

Stara definicja:

View findViewById(int id)

Nowa definicja:

<T extends View> T findViewById(int id)

Więc jeśli masz compileSdkco najmniej 26 lat, oznacza to, że możesz to wykorzystać :)

Eduard B.
źródło
Dzięki i kolejne pytanie. nie mogę znaleźć źródeł sdk26 w menedżerze sdk, więc gdzie mogę znaleźć tę nową definicję?
Eric Zhao,
17
Jeśli usuniemy obsadę, nasze aplikacje będą nadal działać na niższych urządzeniach, prawda?
user1032613
17
@ user1032613: Tak, aplikacje mogą nadal działać na niższych urządzeniach bez żadnego problemu.
Alireza Noorali,
1
Czy spowoduje to zgłoszenie wyjątku, jeśli jest to niewłaściwy typ?
fobbymaster
1
Jakby widok w pliku układu był innego typu? Tak, oczywiście, nadal byłby to plik ClassCastException.
Eduard B.
13

Zgodnie z tym artykułem :

Poniższa funkcja opiera się na automatycznym wnioskowaniu o typie generycznym języka Java, aby wyeliminować potrzebę rzutowania ręcznego:

protected <T extends View> T findViewById(@IdRes int id) {
    return (T) getRootView().findViewById(id);
}
zeroDivider
źródło
11

W starszych wersjach:

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

Z Android Studio 3.0 z SDK 26:

AutoCompleteTextView name = findViewById(R.id.autoCompleteTextView);
Midhun
źródło
16
To nie daje odpowiedzi na pytanie.
Wijay Sharma
1

Android Studio przypomina o usunięciu rzutowania, jeśli używasz wspólnych atrybutów z klasy View , takich jak widoczność lub niektóre typowe metody, takie jak onClick ()

Na przykład:

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

W takim przypadku możesz po prostu napisać:

findViewById(R.id.image_car).setVisibility(View.VISIBLE);
Tim
źródło
2
nadal musisz zadeklarować typ, musiałbyś napisać: findViewById <ImageView> (R.id.image_car) .setVisibility (View.VISIBLE);
Slickelito
Android Studio przypomina nam o usunięciu jawnego rzutowania, ponieważ zostało to zmienione w implementacji automatycznego wnioskowania o typie generycznym języka Java - nie ma to nic wspólnego z używaną metodą.
zeroDivider
1

Android 0, wyczyść przesyłanie

Jedną z rzeczy, które Google ogłasza na IO 2017, jest coś, co nazywa się „odrzuceniem” :). Deweloper Androida nie musi wykonywać ręcznego rzutowania dla findViewById (). Na przykład stary sposób uzyskiwania widoku tekstu przy użyciu funkcji findViewById () wyglądałby mniej więcej tak.

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

Podczas gdy nowy sposób wyglądałby tak

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

To prosta zmiana. Ale dla doświadczonego programisty taki czysty kod może sprawić, że będziesz bardzo szczęśliwy i pomoże ci w nastroju do kodowania :)

Aby móc to zrobić, wystarczyło ustawić wersję skompilowanego zestawu SDK projektu na wersję 26 w aplikacji build.gradle.

Nadal możesz kierować reklamy na wcześniejszą wersję sdk, więc są to nieinwazyjne zmiany.

Teraz prawdziwy problem, jak wyczyścić ten stary kod, który przez cały czas używa rzutowania. Zwłaszcza, gdy masz setki plików aktywności. Możesz to zrobić ręcznie, a może zatrudnić do tego stażystę 😛. Na szczęście dla wszystkich stażystów studio Android jest już przygotowane, aby nam w tym pomóc.

Po umieszczeniu karetki (lub kliknięciu nadmiarowego odlewania) studio Android zasugeruje 2 opcje obsługi nadmiarowego przesyłania.

Najpierw zasugeruje usunięcie tego nadmiarowego rzutowania lub możesz wybrać wyczyść kod. Spowoduje to usunięcie wszystkich nadmiarowych rzutów dla tego pliku. Tak jest lepiej, ale chcemy więcej. Nie chcemy otwierać każdego pliku i czyścić tego po kolei.

Jedną z rzeczy, które sprawiają, że pomysł IntelliJ jest wyjątkowy, jest funkcja zwana zamierzoną akcją. Wszystko, co musisz zrobić, to nacisnąć ctrl + shift + A, a następnie wpisać clean. Następnie wybierz akcję Oczyszczanie kodu i wybierz cały zakres projektu. Dzięki tym kilku prostym krokom Twój kod będzie o wiele bardziej przejrzysty.

Ważną kwestią jest to, że robisz to za pomocą jakiegoś systemu wersjonowania kodu. W ten sposób możesz porównać zmiany wprowadzone przez akcję zamierzoną i przywrócić dowolne pliki, które chcesz.

Skopiowano z oryginalnego posta:

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

daliaessam
źródło
1
Pytanie było why, nie how:The result of findViewById is still View, so i want to know why we don't need to cast the class?
zeroDivider
„Wszystko, co musisz zrobić, to nacisnąć ctrl + shift + A, a następnie wpisać clean”. Co masz na myśli mówiąc „czysty typ”? Jeśli zaczniesz pisać w tym momencie, usuniesz cały plik
Stealth Rabbi
0

W kodzie źródłowym ViewGroupznajduje się rzutowanie zwracanego argumentu. Nie ma więc potrzeby ponownego rzucania:

@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;
}
czynność
źródło