Sie müssen das Ergebnis von findViewById nicht umwandeln?

152

Kürzlich habe ich festgestellt, dass AndroidStudio mich daran erinnert, einige Klassenbesetzungen zu entfernen. Ich erinnere mich, dass wir früher das Ergebnis von findViewById umwandeln mussten, aber jetzt ist es nicht notwendig.

Das Ergebnis von findViewById ist immer noch View. Ich möchte wissen, warum wir die Klasse nicht umwandeln müssen.

Ich kann keine Dokumente finden, die erwähnt wurden. Kann jemand ein Dokument finden?

Eric Zhao
quelle
7
denn jetzt ist es <T extends View> T findViewById(int id)?
Selvin
Sie müssen Casting für alle Operationen durchführen, die in der View-Klasse nicht vorhanden sind, wie im Fall von ImageView. Wenn Sie setImageResource verwenden möchten, müssen Sie findViewById mit ImageView
Gagan Deep
Es ist mir jedoch etwas unangenehm, den Variablentyp auf einen Blick zu kennen, wenn das "redundante" Casting entfernt wird.
Obst

Antworten:

235

Ab API 26 findViewByIdwird Inferenz für den Rückgabetyp verwendet, sodass Sie nicht mehr umwandeln müssen.

Alte Definition:

View findViewById(int id)

Neue Definition:

<T extends View> T findViewById(int id)

Wenn Sie compileSdkalso mindestens 26 Jahre alt sind, bedeutet dies, dass Sie davon Gebrauch machen können :)

Eduard B.
quelle
Danke und noch eine Frage. Ich kann im SDK-Manager keine Quellen für SDK26 finden. Wo finde ich diese neue Definition?
Eric Zhao
17
Wenn wir die Besetzung entfernen, können unsere Apps immer noch auf niedrigeren Geräten ausgeführt werden, oder?
user1032613
17
@ user1032613: Ja, die Apps können problemlos auf niedrigeren Geräten ausgeführt werden.
Alireza Noorali
1
Wird dies eine Ausnahme auslösen, wenn es sich um den falschen Typ handelt?
Fobbymaster
1
Als ob die Ansicht in der Layoutdatei von einem anderen Typ wäre? Ja, natürlich wäre es immer noch ein ClassCastException.
Eduard B.
13

Nach diesem Artikel :

Die folgende Funktion basiert auf der automatischen Typinferenz von Java, um die Notwendigkeit eines manuellen Castings zu beseitigen:

protected <T extends View> T findViewById(@IdRes int id) {
    return (T) getRootView().findViewById(id);
}
zeroDivider
quelle
11

In älteren Versionen:

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

Ab Android Studio 3.0 mit SDK 26:

AutoCompleteTextView name = findViewById(R.id.autoCompleteTextView);
Midhun
quelle
16
Dies liefert keine Antwort auf die Frage.
Wijay Sharma
1

Android Studio erinnert daran, Casting zu entfernen, wenn Sie allgemeine Attribute aus der View- Klasse verwenden, z. B. Sichtbarkeit oder einige gängige Methoden wie onClick ().

Beispielsweise:

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

In diesem Fall können Sie einfach schreiben:

findViewById(R.id.image_car).setVisibility(View.VISIBLE);
Tim
quelle
2
Sie müssen den Typ noch deklarieren, Sie müssten schreiben: findViewById <ImageView> (R.id.image_car) .setVisibility (View.VISIBLE);
Slickelito
Android Studio erinnert uns daran, explizites Casting zu entfernen, da es in der Implementierung der automatischen Typinferenz von Java geändert wurde - es hat nichts mit der von Ihnen verwendeten Methode zu tun.
zeroDivider
1

Android 0, Casting bereinigen

Eines der Dinge, die Google in IO 2017 ankündigt, heißt "wegwerfen" :). Android-Entwickler müssen kein manuelles Casting für findViewById () durchführen. Die alte Methode zum Abrufen einer Textansicht mit findViewById () wäre beispielsweise etwa so.

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

Während der neue Weg so wäre

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

Es ist eine einfache Änderung. Aber für einen erfahrenen Programmierer kann ein sauberer Code wie dieser Sie sehr glücklich machen und hilft bei Ihrer Codierungsstimmung :)

Dazu mussten Sie in Ihrer App build.gradle nur die projektkompilierte SDK-Version auf Version 26 setzen.

Sie können auch weiterhin auf frühere SDK-Versionen abzielen, sodass es sich um nicht aufdringliche Änderungen handelt.

Nun das eigentliche Problem, wie kann man den alten Code bereinigen, der die ganze Zeit Casting verwendet? Vor allem, wenn Sie Hunderte von Aktivitätsdateien mögen. Sie können dies manuell tun oder einen Praktikanten damit beauftragen 😛. Aber zum Glück für all diese Praktikanten hat sich das Android Studio bereits darauf vorbereitet, uns dabei zu helfen.

Wenn Sie Ihr Caret platzieren (oder auf das redundante Casting klicken), schlägt Android Studio 2 Optionen vor, um das redundante Casting zu handhaben.

Zuerst wird vorgeschlagen, diese redundante Umwandlung zu entfernen, oder Sie können Bereinigungscode auswählen. Dadurch wird die gesamte redundante Umwandlung für diese Datei entfernt. Das ist besser, aber wir wollen mehr. Wir möchten nicht jede Datei öffnen und diese nacheinander bereinigen.

Eines der Dinge, die die IntelliJ-Idee zu etwas Besonderem machen, ist eine Funktion, die als Absichtsaktion bezeichnet wird. Alles, was Sie tun müssen, ist Strg + Umschalt + A zu drücken und dann clean einzugeben. Wählen Sie die Aktion Codebereinigung aus und wählen Sie den gesamten Projektumfang aus. Mit diesen wenigen einfachen Schritten wird Ihr Code viel sauberer.

Ein wichtiger Punkt ist, dass Sie dies mit einem Code-Versionierungssystem tun. Auf diese Weise können Sie die Änderungen vergleichen, die durch die Absichtsaktion vorgenommen wurden, und alle gewünschten Dateien zurücksetzen.

Vom Originalbeitrag kopiert:

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

Daliaessam
quelle
1
Die Frage war whynicht how:The result of findViewById is still View, so i want to know why we don't need to cast the class?
zeroDivider
"Alles was Sie tun müssen, ist Strg + Umschalt + A drücken und dann sauber eingeben". Was meinst du mit "Typ sauber"? Wenn Sie an diesem Punkt mit der Eingabe beginnen, löschen Sie die gesamte Datei
Stealth Rabbi
0

Im Quellcode von ViewGroupgibt es eine Umwandlung des return-Arguments. Es besteht also keine Notwendigkeit, erneut zu wirken:

@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;
}
Aktivität
quelle