¿No es necesario emitir el resultado de findViewById?


152

Recientemente descubrí que AndroidStudio me recuerda que elimine parte del reparto de clases. Recuerdo que en el pasado, teníamos que emitir el resultado de findViewById, pero ahora no es necesario.

El resultado de findViewById sigue siendo View, así que quiero saber por qué no necesitamos emitir la clase.

No puedo encontrar ningún documento mencionado, ¿alguien puede encontrar algún documento?


77
porque ahora es <T extends View> T findViewById(int id)?
Selvin

necesita lanzar en caso de cualquier operación que no esté en la clase View, como en el caso de ImageView, si desea usar setImageResource, entonces necesita lanzar findViewById con ImageView
Gagan Deep

Pero me parece un poco incómodo saber el tipo de variable de un vistazo si se elimina el casting "redundante".
Fruta

Respuestas:


235

Comenzando con API 26, findViewById usa inferencia para su tipo de retorno, por lo que ya no tiene que emitir.

Antigua definición:

View findViewById(int id)

Nueva definición:

<T extends View> T findViewById(int id)

Entonces, si compileSdktiene al menos 26 años, significa que puede hacer uso de esto :)


Gracias y otra pregunta. no puedo encontrar fuentes para sdk26 en sdk manager, entonces, ¿dónde puedo encontrar esta nueva definición, por favor?
Eric Zhao

17
Si eliminamos el elenco, nuestras aplicaciones aún pueden ejecutarse en dispositivos inferiores, ¿verdad?
user1032613

17
@ user1032613: Sí, las aplicaciones aún pueden funcionar en dispositivos inferiores sin ningún problema.
Alireza Noorali

1
¿Esto arrojará una excepción si es del tipo incorrecto?
fobbymaster

1
¿Como si la vista en el archivo de diseño es de un tipo diferente? Sí, por supuesto, todavía sería un ClassCastException.
Eduard B.

13

De acuerdo con este artículo :

La siguiente función se basa en la inferencia automática de tipos genéricos de Java para eliminar la necesidad de conversión manual:

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

11

En versiones anteriores:

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

Desde Android Studio 3.0 con SDK 26:

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

16
Esto no proporciona la respuesta de la pregunta.
Wijay Sharma

1

Android Studio recuerda eliminar la transmisión, si usa atributos comunes de la clase View , como visibilidad o algunos métodos comunes, como onClick ()

Por ejemplo:

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

En este caso, simplemente puede escribir:

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

2
todavía tiene que declarar el tipo, debería escribir: findViewById <ImageView> (R.id.image_car) .setVisibility (View.VISIBLE);
Slickelito

Android Studio nos recuerda que eliminemos la conversión explícita porque ha cambiado en la implementación de la inferencia automática de tipos genéricos de Java; no tiene nada que ver con el método que está utilizando.
zeroDivider

1

Android 0, limpieza de casting

Una de las cosas que Google anuncia en IO 2017 es algo que se llama 'desechar' :). El desarrollador de Android no tiene que hacer una conversión manual para findViewById (). Por ejemplo, la forma anterior de obtener una vista de texto usando findViewById () sería algo como esto.

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

Mientras que la nueva forma sería así

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

Es un cambio simple. Pero para un programador experimentado, un código limpio como este puede hacerte muy feliz y te ayuda con tu estado de ánimo de codificación :)

Para poder hacer esto, solo necesita configurar la versión sdk compilada de su proyecto a la versión 26 en su aplicación build.gradle.

Todavía puede apuntar a una versión sdk anterior también, por lo que es un cambio no intrusivo.

Ahora, el verdadero problema, ¿cómo se limpia ese código antiguo que usa la conversión todo este tiempo? Especialmente cuando tienes como cientos de archivos de actividad. Puedes hacerlo manualmente, o tal vez contratar a un interno para hacerlo 😛. Pero afortunadamente para todos esos pasantes, el estudio de Android ya está preparado para ayudarnos con esto.

Cuando pongas tu caret (o hagas clic en el casting redundante), Android Studio te sugerirá 2 opciones para manejar el casting redundante.

Primero, sugerirá eliminar esa conversión redundante o puede seleccionar el código de limpieza. Eliminará toda la conversión redundante para ese archivo. Esto es mejor, pero queremos más. No queremos abrir cada archivo y hacer esta limpieza uno por uno.

Una de las cosas que hace que la idea de IntelliJ sea especial es que es una característica que se llama acción intencional. Todo lo que tienes que hacer es presionar ctrl + shift + A y luego escribir clean. Y seleccione la acción Limpiar código y seleccione todo el alcance del proyecto. Con estos simples pasos, su código será mucho más limpio.

Un punto importante es que haga esto con algún sistema de versiones de código. De esta manera, puede comparar los cambios realizados por la acción intencional y revertir los archivos que desee.

Copiado de la publicación original:

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


1
la pregunta era why, no how:The result of findViewById is still View, so i want to know why we don't need to cast the class?
zeroDivider

"Todo lo que tienes que hacer es presionar ctrl + shift + A y luego escribir clean". ¿Qué quieres decir con "tipo limpio"? Si comienza a escribir en ese punto, borrará todo el archivo
Stealth Rabbi

0

En el código fuente de ViewGroup, hay un reparto del argumento de retorno. Entonces no hay necesidad de lanzar nuevamente:

@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;
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.