Pas besoin de convertir le résultat de findViewById?

152

Récemment, j'ai trouvé qu'AndroidStudio me rappelle de supprimer certains cast de classe. Je me souviens que dans l'ancien temps, nous devions lancer le résultat de findViewById, mais maintenant ce n'est pas nécessaire.

Le résultat de findViewById est toujours View, donc je veux savoir pourquoi nous n'avons pas besoin de lancer la classe?

Je ne trouve aucun document mentionné, est-ce que quelqu'un peut trouver un document?

Eric Zhao
la source
7
parce que maintenant c'est <T extends View> T findViewById(int id)?
Selvin le
vous avez besoin de cast en cas d'opération qui n'est pas là dans la classe View, comme dans le cas d'ImageView, si vous voulez utiliser setImageResource, vous devez lancer findViewById avec ImageView
Gagan Deep
Mais je me sens un peu gênant de connaître le type de variable en un coup d'œil si on supprime le casting "redondant".
Fruit

Réponses:

235

À partir de l'API 26, findViewByIdutilise l'inférence pour son type de retour, vous n'avez donc plus à effectuer de cast.

Ancienne définition:

View findViewById(int id)

Nouvelle définition:

<T extends View> T findViewById(int id)

Donc, si vous avez compileSdkau moins 26 ans, cela signifie que vous pouvez en profiter :)

Eduard B.
la source
Merci et une autre question. Je ne trouve pas les sources de sdk26 dans le gestionnaire de sdk, alors où puis-je trouver cette nouvelle définition s'il vous plaît?
Eric Zhao
17
Si nous supprimons la distribution, nos applications peuvent toujours fonctionner sur des appareils inférieurs, n'est-ce pas?
user1032613
17
@ user1032613: Oui, les applications peuvent toujours fonctionner sur des appareils inférieurs sans aucun problème.
Alireza Noorali
1
Cela lèvera-t-il une exception s'il s'agit du mauvais type?
fobbymaster
1
Comme si la vue dans le fichier de mise en page était d'un type différent? Oui, bien sûr, ce serait toujours un ClassCastException.
Eduard B.
13

D'après cet article :

La fonction suivante repose sur l'inférence automatique de type générique de Java afin d'éliminer le besoin de transtypage manuel:

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

Dans les anciennes versions:

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

Depuis Android Studio 3.0 avec SDK 26:

AutoCompleteTextView name = findViewById(R.id.autoCompleteTextView);
Midhun
la source
16
Cela ne fournit pas la réponse à la question.
Wijay Sharma
1

Android Studio vous rappelle de supprimer la diffusion si vous utilisez des attributs communs de la classe View , comme la visibilité ou certaines méthodes courantes, comme onClick ()

Par exemple:

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

Dans ce cas, vous pouvez simplement écrire:

findViewById(R.id.image_car).setVisibility(View.VISIBLE);
Tim
la source
2
il faut encore déclarer le type, il faudrait écrire: findViewById <ImageView> (R.id.image_car) .setVisibility (View.VISIBLE);
Slickelito
Android Studio nous rappelle de supprimer le cast explicite car il a changé dans l'implémentation de l'inférence automatique de type générique de Java - cela n'a rien à voir avec la méthode que vous utilisez.
zeroDivider
1

Android 0, nettoyer la diffusion

L'une des choses que Google annonce dans IO 2017 est quelque chose qui s'appelle «rejeter» :). Les développeurs Android n'ont pas à effectuer une conversion manuelle pour findViewById (). Par exemple, l'ancienne méthode pour obtenir une vue de texte en utilisant findViewById () serait quelque chose comme ça.

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

Alors que la nouvelle façon serait comme ça

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

C'est un simple changement. Mais pour un programmeur chevronné, un code propre comme celui-ci peut vous rendre très heureux et aider à votre humeur de codage :)

Pour pouvoir le faire, il vous suffit de définir la version sdk compilée de votre projet sur la version 26 dans votre application build.gradle.

Vous pouvez toujours cibler une version antérieure de sdk, il s'agit donc de modifications non intrusives.

Maintenant, le vrai problème, comment nettoyez-vous cet ancien code qui utilise le casting tout ce temps. Surtout lorsque vous avez des centaines de fichiers d'activité. Vous pouvez le faire manuellement, ou peut-être embaucher un stagiaire pour le faire 😛. Mais heureusement pour tous ces stagiaires, le studio Android est déjà prêt à nous aider.

Lorsque vous mettez votre curseur (ou cliquez sur le casting redondant), Android Studio vous proposera 2 options pour gérer le casting redondant.

Tout d'abord, il vous suggérera de supprimer cette distribution redondante ou vous pourrez sélectionner le code de nettoyage. Cela supprimera toute la distribution redondante pour ce fichier. C'est mieux, mais nous en voulons plus. Nous ne voulons pas ouvrir chaque fichier et faire ce nettoyage un par un.

L'une des choses qui rendent IntelliJ idea Special est une fonctionnalité appelée action d'intention. Tout ce que vous avez à faire est d'appuyer sur ctrl + shift + A, puis de taper clean. Et sélectionnez l'action de nettoyage du code, puis sélectionnez toute la portée du projet. Avec ces quelques étapes simples, votre code sera beaucoup plus propre.

Un point important est que vous faites cela avec un système de gestion des versions de code. De cette façon, vous pouvez comparer les modifications apportées par l'action d'intention et rétablir les fichiers de votre choix.

Copié à partir du message d'origine:

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

Daliaessam
la source
1
la question n'était whypas how:The result of findViewById is still View, so i want to know why we don't need to cast the class?
zeroDivider
"Tout ce que vous avez à faire est d'appuyer sur ctrl + shift + A puis de taper clean". Qu'entendez-vous par «type clean»? Si vous commencez à taper à ce moment-là, vous effacerez le fichier entier
Stealth Rabbi
0

Dans le code source de ViewGroup, il y a un cast de l'argument de retour. Il n'est donc pas nécessaire de lancer à nouveau:

@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;
}
activité
la source