Non è necessario trasmettere il risultato di findViewById?


152

Recentemente ho scoperto che AndroidStudio mi ricorda di rimuovere alcuni cast di classe. Ricordo che ai vecchi tempi, dovevamo trasmettere il risultato di findViewById, ma ora non è necessario.

Il risultato di findViewById è ancora Visualizza, quindi voglio sapere perché non è necessario eseguire il cast della classe?

Non riesco a trovare alcun documento menzionato, qualcuno può trovare un documento?


7
perché adesso lo è <T extends View> T findViewById(int id)?
Selvin,

è necessario eseguire il cast in caso di qualsiasi operazione che non è presente nella classe View, come nel caso di ImageView, se si desidera utilizzare setImageResource, è necessario eseguire il cast di findViewById con ImageView
Gagan Deep

Ma mi sembra un po 'scomodo conoscere a colpo d'occhio il tipo di variabile se viene rimosso il cast "ridondante".
Frutta

Risposte:


235

A partire da API 26, findViewByIdutilizza l'inferenza per il tipo di ritorno, quindi non è più necessario eseguire il cast.

Vecchia definizione:

View findViewById(int id)

Nuova definizione:

<T extends View> T findViewById(int id)

Quindi se hai compileSdkalmeno 26 anni, significa che puoi farne uso :)


Grazie e un'altra domanda. non riesco a trovare fonti per sdk26 in sdk manager, quindi dove posso trovare questa nuova definizione per favore?
Eric Zhao,

17
Se rimuoviamo il cast, le nostre app possono ancora funzionare su dispositivi inferiori, giusto?
user1032613

17
@ user1032613: Sì, le app possono ancora funzionare su dispositivi inferiori senza alcun problema.
Alireza Noorali,

1
Ciò genererà un'eccezione se è del tipo sbagliato?
fobbymaster,

1
Come se la vista nel file di layout fosse di tipo diverso? Sì, certo, sarebbe comunque a ClassCastException.
Eduard B.

13

Secondo questo articolo :

La seguente funzione si basa sull'inferenza del tipo di generici automatica di Java per eliminare la necessità di eseguire il cast manuale:

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

11

Nelle versioni precedenti:

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

Da Android Studio 3.0 con SDK 26:

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

16
Questo non fornisce la risposta alla domanda.
Wijay Sharma,

1

Android Studio ricorda di rimuovere il casting, se usi attributi comuni dalla classe View , come visibilità o alcuni metodi comuni, come onClick ()

Per esempio:

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

In questo caso puoi semplicemente scrivere:

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

2
devi ancora dichiarare il tipo, dovresti scrivere: findViewById <ImageView> (R.id.image_car) .setVisibility (View.VISIBLE);
Slickelito,

Android Studio ci ricorda di rimuovere il cast esplicito perché è cambiato nell'implementazione dell'inferenza di tipo automatica generici di Java - non ha nulla a che fare con il metodo che stai usando.
zero Divisore il

1

Android 0, ripulisci il casting

Una delle cose che Google annuncia in IO 2017 è qualcosa che si chiama 'getti via' :). Lo sviluppatore Android non deve eseguire un casting manuale per findViewById (). Ad esempio, il vecchio modo per ottenere una vista di testo usando findViewById () sarebbe qualcosa del genere.

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

Mentre il nuovo modo sarebbe così

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

È un semplice cambiamento. Ma per un programmatore esperto, un codice pulito come questo può renderti molto felice e aiuta con il tuo umore di programmazione :)

Per poterlo fare, devi solo impostare la versione di sdk compilata dal tuo progetto sulla versione 26 nella tua app build.gradle.

Puoi comunque scegliere come target anche la versione precedente di sdk, quindi si tratta di modifiche non intrusive.

Ora il vero problema, come si pulisce quel vecchio codice che utilizza il cast tutto questo tempo. Soprattutto quando hai centinaia di file di attività. Puoi farlo manualmente o magari assumere un stagista per farlo 😛. Ma per fortuna per tutti quegli stagisti, Android Studio è già pronto ad aiutarci con questo.

Quando metti il ​​tuo cursore (o fai clic sul casting ridondante) Android Studio suggerirà 2 opzioni per gestire il casting ridondante.

Innanzitutto ti suggerirà di rimuovere quel cast ridondante o puoi selezionare il codice di pulizia. Rimuoverà tutto il cast ridondante per quel file. Questo è meglio, ma vogliamo di più. Non vogliamo aprire ogni file e ripulirlo uno per uno.

Una delle cose che rendono speciale IntelliJ è che una caratteristica che si chiama azione intenzionale. Tutto quello che devi fare è premere ctrl + maiusc + A e quindi digitare clean. E selezionare l'azione Pulizia codice, quindi selezionare l'intero ambito del progetto. Con questi pochi semplici passaggi il tuo codice sarà molto più pulito.

Un punto importante è che lo fai con un sistema di versioning del codice. In questo modo è possibile confrontare le modifiche apportate dall'azione intenzionale e ripristinare tutti i file desiderati.

Copiato dal post originale:

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


1
la domanda whynon era how:The result of findViewById is still View, so i want to know why we don't need to cast the class?
zero Divisore il

"Tutto quello che devi fare è premere ctrl + maiusc + A e quindi digitare clean". Cosa intendi con "tipo pulito"? Se inizi a digitare a quel punto, cancellerai l'intero file
Stealth Rabbi

0

Nel codice sorgente di ViewGroup, c'è un cast dell'argomento return. Quindi non è necessario eseguire nuovamente il cast:

@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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.