Não há necessidade de converter o resultado de findViewById?


152

Recentemente, descobri que o AndroidStudio me lembra de remover um elenco de classe. Lembro que, nos velhos tempos, precisamos lançar o resultado de findViewById, mas agora não é necessário.

O resultado de findViewById ainda é View, então quero saber por que não precisamos transmitir a classe?

Não consigo encontrar nenhum documento mencionado, alguém pode encontrar algum documento?


7
porque agora é <T extends View> T findViewById(int id)?
Selvin

você precisa de qualidade em caso de qualquer operação que não está lá em Ver classe, como no caso de ImageView, Se você quiser usar setImageResource, então você precisa elenco findViewById com ImageView
Gagan Profundo

Mas me sinto um pouco inconveniente ao saber rapidamente o tipo de variável se removida a conversão "redundante".
Fruit

Respostas:


235

A partir da API 26, findViewByIdusa inferência para seu tipo de retorno, para que você não precise mais transmitir.

Antiga definição:

View findViewById(int id)

Nova definição:

<T extends View> T findViewById(int id)

Então, se você compileSdktem pelo menos 26 anos, significa que você pode fazer uso disso :)


Obrigado, e outra pergunta. não consigo encontrar fontes para sdk26 no sdk manager, então onde posso encontrar essa nova definição, por favor?
Eric Zhao

17
Se removermos a transmissão, nossos aplicativos ainda poderão ser executados em dispositivos inferiores, certo?
user1032613

17
@ user1032613: Sim, os aplicativos ainda podem funcionar em dispositivos inferiores sem nenhum problema.
Alireza Noorali 12/12

1
Isso gerará uma exceção se for do tipo errado?
fobbymaster 24/02

1
Como se a visualização no arquivo de layout fosse de um tipo diferente? Sim, é claro, ainda seria um ClassCastException.
Eduard B.

13

De acordo com este artigo :

A função a seguir conta com a inferência automática de tipo genérica do Java para eliminar a necessidade de conversão manual:

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

11

Nas versões mais antigas:

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

No Android Studio 3.0 com SDK 26:

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

16
Isso não fornece a resposta da pergunta.
Wijay Sharma

1

O Android Studio lembra a remoção da transmissão, se você usar atributos comuns da classe View , como visibilidade ou alguns métodos comuns, como onClick ()

Por exemplo:

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

Nesse caso, você pode simplesmente escrever:

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

2
você ainda precisa declarar o tipo, teria que escrever: findViewById <ImageView> (R.id.image_car) .setVisibility (View.VISIBLE);
Slickelito 18/10

O Android Studio nos lembra de remover a conversão explícita porque foi alterada na implementação da inferência automática de tipo genérica do Java - não tem nada a ver com o método que você está usando.
ZeroDivider 23/04/19

1

Android 0, limpar elenco

Uma das coisas que o Google anuncia no IO 2017 é algo chamado 'rejeitar' :). O desenvolvedor do Android não precisa fazer uma transmissão manual para findViewById (). Por exemplo, a maneira antiga de obter uma exibição de texto usando findViewById () seria algo como isto.

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

Enquanto o novo caminho seria assim

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

É uma simples mudança. Mas para um programador experiente, um código limpo como esse pode deixá-lo muito feliz e ajuda no seu humor de codificação :)

Para poder fazer isso, você só precisava definir a versão sdk compilada do projeto para a versão 26 em seu aplicativo build.gradle.

Você ainda pode segmentar a versão anterior do sdk também, por isso é uma alteração não intrusiva.

Agora, o verdadeiro problema, como você limpa esse código antigo que usa a conversão o tempo todo. Especialmente quando você tem centenas de arquivos de atividade. Você pode fazê-lo manualmente, ou talvez contrate um estagiário para fazê-lo 😛. Mas, felizmente, para todos os estagiários, o Android Studio já está preparado para nos ajudar com isso.

Quando você coloca o cursor (ou clica na transmissão redundante), o Android Studio sugere 2 opções para lidar com a transmissão redundante.

Primeiro, ele sugerirá remover essa conversão redundante ou você pode selecionar o código de limpeza. Ele removerá toda a conversão redundante para esse arquivo. Isso é melhor, mas queremos mais. Não queremos abrir cada arquivo e limpar isso um por um.

Uma das coisas que tornam o IntelliJ ideal é o recurso que é chamado de ação intencional. Tudo o que você precisa fazer é pressionar ctrl + shift + A e depois digitar clean. E selecione Ação de limpeza de código e selecione todo o escopo do projeto. Com essas etapas simples, seu código ficará muito mais limpo.

Um ponto importante é que você faz isso com algum sistema de versão de código. Dessa forma, você pode comparar as alterações que estão sendo feitas pela ação de intenção e reverter os arquivos que desejar.

Copiado da postagem original:

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


1
a pergunta era why, não how:The result of findViewById is still View, so i want to know why we don't need to cast the class?
zeroDivider 24/12/19

"Tudo o que você precisa fazer é pressionar ctrl + shift + A e depois digitar clean". O que você quer dizer com "tipo limpo"? Se você começar a digitar nesse ponto, irá apagar o arquivo inteiro
Stealth Rabbi

0

No código fonte de ViewGroup, há uma conversão do argumento de retorno. Portanto, não há necessidade de transmitir novamente:

@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;
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.