A Data Binding Library gera classes de vinculação que são usadas para acessar as variáveis e visualizações do layout. Esta página mostra como criar e personalizar as classes de vinculação geradas.
A classe de vinculação gerada vincula as variáveis de layout às visualizações dentro do layout. O nome e o pacote da classe de vinculação podem ser personalizados. Todas as classes de vinculação geradas são herdadas da classe ViewDataBinding
.
Uma classe de vinculação é gerada para cada arquivo de layout. Por padrão, o nome da classe é baseado no nome do arquivo de layout, convertido no Pascal Case e com o sufixo Binding. O nome do arquivo do layout acima é activity_main.xml
, então a classe gerada correspondente é ActivityMainBinding
. Essa classe contém todas as vinculações das propriedades de layout (por exemplo, a variável user
) para as visualizações do layout e sabe como atribuir valores para as expressões de vinculação.
Criar um objeto de vinculação
O objeto de vinculação é criado imediatamente após inflar o layout para garantir que a hierarquia de visualização não seja modificada antes de se vincular às visualizações com expressões no layout. O método mais comum para vincular o objeto a um layout é usar os métodos estáticos na classe de vinculação. É possível inflar a hierarquia de visualização e vincular o objeto a ela usando o método inflate()
da classe de vinculação, conforme mostrado no exemplo a seguir.
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding: MyLayoutBinding = MyLayoutBinding.inflate(layoutInflater) setContentView(binding.root) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MyLayoutBinding binding = MyLayoutBinding.inflate(getLayoutInflater()); setContentView(binding.root); }
Há uma versão alternativa do método inflate()
que usa um objeto ViewGroup
, além do objeto LayoutInflater
, conforme mostrado no exemplo a seguir.
Kotlin
val binding: MyLayoutBinding = MyLayoutBinding.inflate(getLayoutInflater(), viewGroup, false)
Java
MyLayoutBinding binding = MyLayoutBinding.inflate(getLayoutInflater(), viewGroup, false);
Se o layout foi inflado usando outro mecanismo, ele pode ser vinculado separadamente da seguinte maneira:
Kotlin
val binding: MyLayoutBinding = MyLayoutBinding.bind(viewRoot)
Java
MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);
Às vezes, não é possível saber o tipo de vinculação com antecedência. Nesses casos, a vinculação pode ser criada usando a classe DataBindingUtil
, conforme demonstrado no seguinte snippet de código:
Kotlin
val viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent) val binding: ViewDataBinding? = DataBindingUtil.bind(viewRoot)
Java
View viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent); ViewDataBinding binding = DataBindingUtil.bind(viewRoot);
Se você estiver usando itens de vinculação de dados dentro de um adaptador Fragment
, ListView
ou RecyclerView
, talvez prefira usar os métodos inflate()
das classes de vinculação ou DataBindingUtil
, como mostrado no exemplo de código a seguir.
Kotlin
val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false) // or val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)
Java
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false); // or ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
Visualizações com códigos
A Data Binding Library cria um campo imutável na classe de vinculação para cada visualização que tenha um código no layout. Por exemplo, a Data Binding Library cria os campos firstName
e lastName
do tipo TextView
a partir do seguinte layout:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
android:id="@+id/firstName"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"
android:id="@+id/lastName"/>
</LinearLayout>
</layout>
A biblioteca extrai as visualizações que incluem os códigos da hierarquia da visualização em uma única passagem. Esse mecanismo pode ser mais rápido do que chamar o método findViewById()
para todas as visualizações no layout.
Os códigos não são tão necessários quanto são sem a vinculação de dados, mas ainda há alguns casos em que o acesso às visualizações a partir do código é necessário.
Variáveis
A Data Binding Library gera métodos do acessador para cada variável declarada no layout. Por exemplo, o layout a seguir gera métodos setter e getter na classe de vinculação para as variáveis user
, image
e note
.
<data>
<import type="android.graphics.drawable.Drawable"/>
<variable name="user" type="com.example.User"/>
<variable name="image" type="Drawable"/>
<variable name="note" type="String"/>
</data>
ViewStubs
Ao contrário das visualizações normais, os objetos ViewStub
começam como uma visualização invisível. Quando se tornam visíveis ou são explicitamente instruídos a inflarem, os objetos se substituem no layout, inflando outro layout.
Como o ViewStub
basicamente desaparece da hierarquia de visualização, a visualização no objeto de vinculação também precisa desaparecer para permitir a reivindicação pela coleta de lixo. Como as visualizações são finais, um objeto ViewStubProxy
substitui o ViewStub
na classe de vinculação gerada, oferecendo acesso ao ViewStub
quando ele existe e também a hierarquia de visualização aumentada quando o ViewStub
foi aumentado.
Ao inflar outro layout, uma vinculação precisa ser estabelecida para o novo layout.
Portanto, o ViewStubProxy
precisa ouvir o ViewStub
OnInflateListener
e estabelecer a vinculação quando necessário. Como só pode haver um listener em um determinado momento, o ViewStubProxy
permite que você defina um OnInflateListener
, que é chamado que a vinculação é estabelecida.
Vinculação imediata
Quando uma variável ou um objeto observável muda, a vinculação é programada para mudar antes do próximo frame. No entanto, há momentos em que a vinculação precisa ser executada imediatamente. Para forçar a execução, use o método executePendingBindings()
.
Vinculação avançada
Variáveis dinâmicas
Às vezes, a classe de vinculação específica não é conhecida. Por exemplo, uma operação RecyclerView.Adapter
em layouts arbitrários não conhece a classe de vinculação específica. Ele ainda precisa atribuir o valor de vinculação durante a chamada ao método onBindViewHolder()
.
No exemplo a seguir, todos os layouts vinculados ao RecyclerView
têm uma variável item
. O objeto BindingHolder
tem um método getBinding()
que retorna a classe base ViewDataBinding
.
Kotlin
override fun onBindViewHolder(holder: BindingHolder, position: Int) { item: T = items.get(position) holder.binding.setVariable(BR.item, item); holder.binding.executePendingBindings(); }
Java
public void onBindViewHolder(BindingHolder holder, int position) { final T item = items.get(position); holder.getBinding().setVariable(BR.item, item); holder.getBinding().executePendingBindings(); }
Linha de execução em segundo plano
É possível mudar seu modelo de dados em uma linha de execução em segundo plano, desde que não seja uma coleção. A vinculação de dados localiza cada variável/campo durante a avaliação para evitar problemas de simultaneidade.
Nomes de classes de vinculação personalizados
Por padrão, uma classe de vinculação é gerada com base no nome do arquivo de layout, começando com uma letra maiúscula, removendo os sublinhados (_), com maiúscula na letra seguinte e colocando a palavra Binding como sufixo. A classe é colocada em um pacote databinding
no pacote do módulo. Por exemplo, o arquivo de layout contact_item.xml
gera a classe ContactItemBinding
. Se o pacote do módulo for com.example.my.app
, a classe de vinculação será colocada no pacote com.example.my.app.databinding
.
As classes de vinculação podem ser renomeadas ou colocadas em pacotes diferentes, ajustando o atributo class
do elemento data
. Por exemplo, o layout a seguir gera a classe de vinculação ContactItem
no pacote databinding
no módulo atual:
<data class="ContactItem">
…
</data>
É possível gerar a classe de vinculação em um pacote diferente, acrescentando um prefixo ao nome da classe com um ponto. O exemplo a seguir gera a classe de vinculação no pacote do módulo:
<data class=".ContactItem">
…
</data>
Também é possível usar o nome completo do pacote no qual você quer que a classe de vinculação seja gerada. O exemplo a seguir cria a classe de vinculação ContactItem
no pacote com.example
.
<data class="com.example.ContactItem">
…
</data>
Outros recursos
Para saber mais sobre vinculação de dados, consulte os seguintes recursos adicionais.
Amostras
- Amostras da Android Data Binding Library (link em inglês)
Codelabs
- Codelab da Android Data Binding Library (link em inglês)
Postagens do blog
- Vinculação de dados: lições aprendidas (em inglês)