Clases de vinculación generadas

La biblioteca de vinculación de datos genera clases de vinculación que se utilizan para acceder a las variables y vistas del diseño. En esta página, se muestra cómo crear y personalizar las clases de vinculación generadas.

La clase de vinculación generada vincula las variables de diseño con las vistas dentro del diseño. Se pueden personalizar el nombre y el paquete de la clase de vinculación. Todas las clases de vinculación generadas se heredan de la clase ViewDataBinding.

Se genera una clase de vinculación para cada archivo de diseño. De forma predeterminada, el nombre de la clase se basa en el nombre del archivo de diseño. Lo que cambia es que se usa el formato pascalCase en la primera letra de cada palabra y se agrega el sufijo Binding. El nombre de archivo de diseño anterior es activity_main.xml, por lo que la clase generada correspondiente es ActivityMainBinding. Esta clase contiene todas las vinculaciones, desde las propiedades de diseño (por ejemplo, la variable user) hasta las vistas del diseño, y sabe cómo asignar valores para las expresiones de vinculación.

Crea un objeto de vinculación

El objeto de vinculación se crea inmediatamente después de aumentar el diseño para garantizar que la jerarquía de vistas no se modifique antes de vincularse a las vistas con expresiones dentro del diseño. El método más común para vincular el objeto a un diseño es usar los métodos estáticos en la clase de vinculación. Puedes aumentar la jerarquía de vistas y vincular el objeto a ella usando el método inflate() de la clase de vinculación, como se muestra en el siguiente ejemplo:

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);
    }

    

Existe una versión alternativa del método inflate() que toma un objeto ViewGroup además del LayoutInflater , como se muestra en el siguiente ejemplo:

Kotlin

    val binding: MyLayoutBinding = MyLayoutBinding.inflate(getLayoutInflater(), viewGroup, false)

    

Java

    MyLayoutBinding binding = MyLayoutBinding.inflate(getLayoutInflater(), viewGroup, false);

    

Si el diseño se aumentó con un mecanismo diferente, se puede vincular por separado de la siguiente manera:

Kotlin

    val binding: MyLayoutBinding = MyLayoutBinding.bind(viewRoot)

    

Java

    MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);

    

A veces, el tipo de vinculación no se puede conocer de antemano. En esos casos, la vinculación se puede crear utilizando la clase DataBindingUtil, como se muestra en el siguiente fragmento 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);

    

Si usas elementos de vinculación de datos dentro de un adaptador Fragment, ListView o RecyclerView, es posible que prefieras usar los métodos inflate() de las clases de vinculación o DataBindingUtil, como se muestra en el siguiente ejemplo de código:

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);

    

Vistas con ID

La biblioteca de vinculación de datos crea un campo inmutable en la clase de vinculación para cada vista que tiene un ID en el diseño. Por ejemplo, la biblioteca de vinculación de datos crea los campos firstName y lastName de tipo TextView a partir del siguiente diseño:

<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>
    

La biblioteca extrae las vistas, incluidos los ID, de la jerarquía de vistas en un solo pase. Este mecanismo puede ser más rápido que llamar al método findViewById() para cada vista en el diseño.

Los ID no son tan necesarios como lo son sin vinculación de datos, pero todavía hay algunas instancias en las que el acceso a las vistas sigue siendo necesario desde el código.

Variables

La biblioteca de vinculación de datos genera métodos de acceso para cada variable declarada en el diseño. Por ejemplo, el siguiente diseño genera métodos set y get en la clase de vinculación para las variables user, image y 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

A diferencia de las vistas normales, los objetos ViewStub comienzan como una vista invisible. Cuando se hacen visibles o se les dice explícitamente que se aumenten, se reemplazan en el diseño aumentando otro diseño.

Debido a que ViewStub esencialmente desaparece de la jerarquía de vistas, la vista en el objeto de vinculación también debe desaparecer para permitir que sea reclamada por la recolección de elementos no utilizados. Debido a que las vistas son definitivas, un objeto ViewStubProxy reemplaza a ViewStub en la clase de vinculación generada, lo que te otorga acceso a ViewStub cuando existe y acceso a la jerarquía de vistas aumentada después de que se aumenta ViewStub.

Si se aumenta otro diseño, se debe establecer una vinculación para el diseño nuevo. Por lo tanto, ViewStubProxy debe escuchar a ViewStub OnInflateListener y establecer la vinculación cuando sea necesario. Como solo puede existir un objeto de escucha en un momento dado, ViewStubProxy te permite establecer un OnInflateListener, al que llama después de establecer la vinculación.

Vinculación inmediata

Cuando cambia una variable o un objeto observable, la vinculación está programada para cambiar antes del siguiente marco. Sin embargo, hay momentos en que la vinculación debe ejecutarse inmediatamente. Para forzar la ejecución, usa el método executePendingBindings().

Vinculación avanzada

Variables dinámicas

A veces, no se conoce la clase de vinculación específica. Por ejemplo, un RecyclerView.Adapter que funciona con diseños arbitrarios no conoce la clase de vinculación específica. Debe asignar de todas formas el valor de vinculación durante la llamada al método onBindViewHolder().

En el siguiente ejemplo, se muestran todos los diseños que la RecyclerView vincula para tener una variable de item. El objeto BindingHolder tiene un método getBinding() que muestra la clase 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();
    }

    

Subprocesos en segundo plano

Puedes cambiar tu modelo de datos en un subproceso en segundo plano, siempre que no sea una colección. La vinculación de datos localiza cada variable/campo durante la evaluación para evitar problemas de concurrencia.

Nombres de clases de vinculación personalizadas

De forma predeterminada, se genera una clase de vinculación basada en el nombre del archivo de diseño, que comienza con una letra mayúscula. Además, se quitan los guiones bajos (_), se usa mayúscula en la palabra que sigue y se usa el sufijo Binding. La clase se coloca en un paquete de databinding debajo del paquete del módulo. Por ejemplo, el archivo de diseño contact_item.xml genera la clase ContactItemBinding. Si el paquete del módulo es com.example.my.app, la clase de vinculación se coloca en el paquete com.example.my.app.databinding.

Las clases Binding se pueden volver a nombrar o disponer en paquetes diferentes ajustando el atributo class del elemento data. Por ejemplo, el siguiente diseño genera la clase de vinculación ContactItem en el paquete databinding del módulo actual:

<data class="ContactItem">
        …
    </data>
    

Puedes generar la clase de vinculación en un paquete diferente si le antepones un punto al nombre de la clase. En el siguiente ejemplo, se genera la clase de vinculación en el paquete del módulo:

<data class=".ContactItem">
        …
    </data>
    

También puedes usar el nombre completo del paquete en el que deseas que se genere la clase de vinculación. En el siguiente ejemplo, se crea la clase de vinculación ContactItem en el paquete com.example:

<data class="com.example.ContactItem">
        …
    </data>
    

Recursos adicionales

Para obtener más información sobre la vinculación de datos, consulta los siguientes recursos adicionales.

Ejemplos

Codelabs

Entradas de blog