Cómo trabajar con objetos de datos observables

La observabilidad es la capacidad de un objeto para notificar a otros sobre cambios en sus datos. La biblioteca de vinculación de datos te permite hacer que objetos, campos o colecciones sean observables.

Se puede usar cualquier objeto para la vinculación de datos, pero modificar el objeto no hace que la IU se actualice automáticamente. La vinculación de datos se puede utilizar para otorgar a los objetos de datos la capacidad de notificar a otros objetos, conocidos como objetos de escucha, cuando cambian sus datos. Hay tres tipos diferentes de clases observables: objetos, campos y colecciones.

Cuando uno de esos objetos de datos observables está vinculado a la IU y una propiedad del objeto de datos cambia, la IU se actualiza automáticamente.

Campos observables

Crear clases que implementen la interfaz Observable requiere un poco de trabajo. Hacerlo no valdría la pena si las clases solo tuvieran unas pocas propiedades. En este caso, puedes usar la clase genérica Observable y las siguientes clases primitivas específicas para que los campos sean observables:

Los campos observables son objetos observables autónomos que tienen un solo campo. Las versiones primitivas evitan la conversión boxing y unboxing durante las operaciones de acceso. Para usar este mecanismo, crea una propiedad public final en el lenguaje de programación Java o una propiedad de solo lectura en Kotlin, como se muestra en el siguiente ejemplo:

Kotlin

    class User {
        val firstName = ObservableField<String>()
        val lastName = ObservableField<String>()
        val age = ObservableInt()
    }

    

Java

    private static class User {
        public final ObservableField<String> firstName = new ObservableField<>();
        public final ObservableField<String> lastName = new ObservableField<>();
        public final ObservableInt age = new ObservableInt();
    }

    

Para acceder al valor del campo, usa los métodos de acceso set() y get(), o bien la sintaxis de la propiedad Kotlin:

Kotlin

    user.firstName = "Google"
    val age = user.age

    

Java

    user.firstName.set("Google");
    int age = user.age.get();

    

Colecciones observables

Algunas apps usan estructuras dinámicas para almacenar datos. Las colecciones observables permiten acceder a esas estructuras mediante una clave. La clase ObservableArrayMap es útil cuando la clave es un tipo de referencia (por ejemplo, String), como se muestra en el siguiente ejemplo:

Kotlin

    ObservableArrayMap<String, Any>().apply {
        put("firstName", "Google")
        put("lastName", "Inc.")
        put("age", 17)
    }

    

Java

    ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
    user.put("firstName", "Google");
    user.put("lastName", "Inc.");
    user.put("age", 17);

    

En el diseño, se puede encontrar el mapa utilizando las claves de string de la siguiente manera:

<data>
        <import type="android.databinding.ObservableMap"/>
        <variable name="user" type="ObservableMap<String, Object>"/>
    </data>
    …
    <TextView
        android:text="@{user.lastName}"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView
        android:text="@{String.valueOf(1 + (Integer)user.age)}"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    

La clase ObservableArrayList es útil cuando la clave es un número entero, por ejemplo:

Kotlin

    ObservableArrayList<Any>().apply {
        add("Google")
        add("Inc.")
        add(17)
    }

    

Java

    ObservableArrayList<Object> user = new ObservableArrayList<>();
    user.add("Google");
    user.add("Inc.");
    user.add(17);

    

En el diseño, se puede acceder a la lista por medio de los índices, como se muestra en el siguiente ejemplo:

<data>
        <import type="android.databinding.ObservableList"/>
        <import type="com.example.my.app.Fields"/>
        <variable name="user" type="ObservableList<Object>"/>
    </data>
    …
    <TextView
        android:text='@{user[Fields.LAST_NAME]}'
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView
        android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}'
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    

Objetos observables

Una clase que implementa la interfaz Observable permite registrar objetos de escucha que desean recibir notificaciones de cambios de propiedad en el objeto observable.

La interfaz Observable tiene un mecanismo para agregar y quitar objetos de escucha, pero debes decidir cuándo se envían las notificaciones. Para facilitar el desarrollo, la biblioteca de vinculación de datos proporciona la clase BaseObservable, que implementa el mecanismo de registro del objeto de escucha. La clase de datos que implementa BaseObservable es responsable de notificar cuándo cambian las propiedades. Para ello, asigna una anotación Bindable al método get y llama al método notifyPropertyChanged() en el método set, como se muestra en el siguiente ejemplo:

Kotlin

    class User : BaseObservable() {

        @get:Bindable
        var firstName: String = ""
            set(value) {
                field = value
                notifyPropertyChanged(BR.firstName)
            }

        @get:Bindable
        var lastName: String = ""
            set(value) {
                field = value
                notifyPropertyChanged(BR.lastName)
            }
    }
    

Java

    private static class User extends BaseObservable {
        private String firstName;
        private String lastName;

        @Bindable
        public String getFirstName() {
            return this.firstName;
        }

        @Bindable
        public String getLastName() {
            return this.lastName;
        }

        public void setFirstName(String firstName) {
            this.firstName = firstName;
            notifyPropertyChanged(BR.firstName);
        }

        public void setLastName(String lastName) {
            this.lastName = lastName;
            notifyPropertyChanged(BR.lastName);
        }
    }

    

La vinculación de datos genera una clase denominada BR en el paquete del módulo que contiene los ID de los recursos utilizados para la vinculación de datos. La anotación Bindable genera una entrada en el archivo de la clase BR durante la compilación. Si no se puede cambiar la clase base para las clases de datos, se puede implementar la interfaz Observable utilizando un objeto PropertyChangeRegistry a fin de registrar y notificar a los objetos de escucha de manera eficiente.

Recursos adicionales

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

Ejemplos

Codelabs

Entradas de blog