Para demonstrar os exemplos, vamos utilizar o Todo, um App capaz de cadastrar e listar tarefas:
Autor(a)
Alex Felipe
Alex é instrutor e desenvolvedor e possui experiência em Java, Kotlin, Android. Atualmente cria conteúdo no canal https://www.youtube.com/@AlexFelipeDev.
Inscreva-se em nossa Newsletter
Fique por dentro de conteúdos, insights e oportunidades do universo tech. Receba novidades e lançamentos direto no seu e-mail.
As implementações foram feitas da seguinte maneira:
Lista de tarefas em uma Activity com um RecyclerView
Formulário de criação de tarefa em um Fragment
O motivo de utilizar essas entidades, é demonstrar as diferentes implementações com o View Binding.
Como vimos, o View Binding trata-se de uma alternativa para buscar Views do Android, porém, por padrão, temos acesso ao findViewById(). Então, por que deveríamos considerar o View Binding?
Os principais motivos para o uso do View Binding são:
Escrever um código mais fácil para interagir com as Views
Obter mais segurança ao acessar uma View:
segurança de nulo: o View Binding cria diretamente as referências com a View, portanto, não há risco de buscar uma View que não existe no layout.
segurança de tipo: cada campo encontrado no layout pelo View Binding, mantém o mesmo tipo apresentado no arquivo de layout, dessa forma, evitamos qualquer problema de casting.
Agora que conhecemos os motivos para utilizar o View Binding, vamos começar com a configuração.
Configurando o View Binding no projeto Android
O View Binding é configurado por módulo de um projeto Android, portanto, dentro do arquivo build.gradle do módulo App, adicionamos a seguinte instrução:
Basta sincronizar que o View Binding está configurado! Simples assim. 🙂
Como o View Binding funciona?
Após habilitar o View Binding, automaticamente, ele gerará classes que representam cada arquivo de layout do módulo no seguinte padrão: nomeDoLayoutBinding.
Dentro do projeto temos os seguintes arquivos de layout:
formulario_nota_activity.xml
formulario_nota_fragment.xml
item_nota.xml
lista_notas_activity.xml
Isso significa que ao configurar o View Binding, ele gera as seguintes classes para os layouts:
FormularioNotaActivityBinding
FormularioNotaFragmentBinding
ItemNotaBinding
ListaNotasActivity
A partir dessas referências, podemos acessar as views de cada layout considerando os destaques do View Binding.
Para começar o nosso exemplo, vamos acessar a ListaNotasActivity:
classListaNotasActivity : AppCompatActivity(R.layout.lista_notas_activity) {
// restante do códigooverridefunonCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val recyclerView = findViewById<RecyclerView>(R.id.lista_notas_activity_recyclerview)
recyclerView.adapter = adapter
configuraFab()
}
privatefunconfiguraFab() {
val fab = findViewById<ExtendedFloatingActionButton>(R.id.lista_notas_activity_fab)
fab.setOnClickListener {
// restante do código
}
}
}
Note que utilizamos o findViewById() para buscar o RecyclerView e o ExtendedFloatingActionButton. Dado esse exemplo, vamos adaptar o código para usar o View Binding.
Utilizando o View Binding na Activity
Para utilizar o View Binding, primeiro precisamos realizar o processo de inflar a View. Para isso, no onCreate(), acesse a referência ListaNotasBinding e chame o método inflate() enviando o layoutInflater da Activity:
overridefunonCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ListaNotasActivityBinding.inflate(layoutInflater)
// restante do código
}
Observe que criamos a variável binding, esse padrão de nomeação é comum quando realizamos o processo de binding de View com o View Binding.
A partir da variável binding, podemos acessar as views, como, por exemplo, o RecyclerView:
overridefunonCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ListaNotasActivityBinding.inflate(layoutInflater)
val recyclerView = binding.listaNotasActivityRecyclerview
recyclerView.adapter = adapter
configuraFab()
}
E para ter um acesso por todos os membros, podemos até mesmo tornar o binding uma property lazy:
classListaNotasActivity : AppCompatActivity(R.layout.lista_notas_activity) {
privateval binding by lazy {
ListaNotasActivityBinding.inflate(layoutInflater)
}
overridefunonCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val recyclerView = binding.listaNotasActivityRecyclerview
// restante do código
}
// restante do códigoprivatefunconfiguraFab() {
val fab = binding.listaNotasActivityFab
// restante do código
}
}
Se testarmos o App apenas com essa modificação, o RecyclerView e o FAB não funcionam! Isso acontece porque precisamos vincular a View do View Binding com a Activity, para isso, podemos chamar o método setContentView() enviando o root do binding
classListaNotasActivity : AppCompatActivity() {
privateval adapter by lazy {
ListaNotasAdapter(this)
}
privateval binding by lazy {
ListaNotasActivityBinding.inflate(layoutInflater)
}
overridefunonCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val recyclerView = binding.listaNotasActivityRecyclerview
recyclerView.adapter = adapter
configuraFab()
setContentView(binding.root)
}
// restante do código
}
A partir do momento que utilizamos o View Binding, é importante remover a referência do layout no construtor da Activity ou em um setContentView().
Com esse ajuste, o nosso código funciona sem qualquer problema!
Implementando o View Binding no RecyclerView
No ListaNotasAdapter do RecyclerView, o uso do ViewBinding é feito durante a criação do ViewHolder. A técnica é similar ao da Activity, mas seguindo os padrões de inflate do adapter:
Observe que a grande diferença é que o ViewHolder recebe o View Binding do layout desejado, nesse caso, o ItemNotaBinding. Então, é enviada a view com o binding.root para o construtor do RecyclerView.ViewHolder() e o parâmetro binding pode ser utilizado para buscar as views desejadas.
Utilizando o View Binding no Fragment
No Fragment temos um cenário diferente. Pois, devido ao processo de recriar a View cada vez que ele é acessado, somos responsáveis em criar o View Binding e limpá-lo quando a view é destruída:
Da mesma maneira que foi feito na Activity, no Fragment também é importante remover a referência de layout no construtor.
Essa possível implementação é sugerida na página da documentação, e explica que mesmo usando o null assertion operator (!!), bastante perigoso por conta de NPE, não corremos o risco de NPE se acessarmos o binding nos estados de ciclo de vida do Fragment entre onCreateView() e onDestroyView():
Com base no fluxograma, podemos acessar o binding a partir do onViewCreated(), até o onSaveInstanceState().
Tempo de build e ignorando layouts com View Binding
Por gerar código, o View Binding também custa tempo de build que, segundo a documentação, por não ter anotações durante a configuração, ele é mais rápido que alternativas como o Data Binding.
Além disso, se preferir evitar a geração de código em layouts específicos, seja pelo tempo de build ou por não usar referências do layout, como é o caso da FormularioNotaActivity, que tem apenas um container de Fragment, podemos ignorar layouts adicionando tools:viewBindingIgnore="true" no root da View do layout.
Considerando o exemplo da FormularioNotaActivity, fica da seguinte maneira:
Com esse ajuste, a classe FormularioNotaActivity não é mais gerada pelo processo de build do projeto.
Conclusão
O View Binding é a técnica mais recente e recomenda pela equipe do Android, portanto, se atualmente você utiliza o synthetic, o recomendado é que migre para o View Binding. Caso mantenha o uso apenas do findViewById(), você pode considerar o uso do View Binding, pois, além de facilitar a busca das views, também existe o benefício de evitar NPE ou problemas de casting.
Código fonte desenvolvido
Caso tenha interesse em consultar as mudanças do projeto, confira este commit.