Trabalhar com objetos de dados observáveis

Observabilidade é a capacidade de um objeto de notificar outros sobre mudanças nos dados deles. A Data Binding Library permite que você faça com que objetos, campos ou coleções sejam observáveis.

Qualquer objeto antigo pode ser usado para vinculação de dados, mas a modificação do objeto não faz com que a IU seja atualizada automaticamente. A vinculação de dados pode ser usada para possibilitar que seus objetos de dados notifiquem outros objetos, conhecidos como listeners, quando os dados deles mudarem. Existem três tipos de classes observáveis: objetos, campos e coleções.

Quando um desses objetos de dados observáveis é vinculado à IU e uma propriedade do objeto de dados muda, a IU é atualizada automaticamente.

Campos observáveis

Criar classes que implementem a interface Observable envolve certo trabalho, que pode não valer a pena caso suas classes tenham apenas algumas propriedades. Nesse caso, você pode usar a classe genérica Observable e as classes específicas de primitivos a seguir para tornar os campos observáveis:

Os campos observáveis são objetos observáveis independentes que têm um único campo. As versões primitivas evitam a conversão boxing e unboxing durante operações de acesso. Para usar esse mecanismo, crie uma propriedade public final na linguagem de programação Java ou uma propriedade somente de leitura em Kotlin, conforme mostrado no exemplo a seguir:

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 acessar o valor do campo, use os métodos do acessador set() e get() ou use a sintaxe de propriedade do Kotlin (link em inglês):

Kotlin

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

    

Java

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

    

Coleções observáveis

Alguns apps usam estruturas dinâmicas para reter dados. As coleções observáveis permitem acessar essas estruturas usando uma chave. A classe ObservableArrayMap é útil quando a chave é um tipo de referência, como String, conforme mostrado no exemplo a seguir:

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

    

No layout, o mapa pode ser encontrado usando as chaves da string, da seguinte maneira:

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

A classe ObservableArrayList é útil quando a chave é um número inteiro, conforme mostrado a seguir:

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

    

No layout, a lista pode ser acessada por meio dos índices, conforme mostrado no exemplo a seguir:

<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 observáveis

Uma classe que implementa a interface Observable permite registrar listeners que queiram ser notificados sobre mudanças em propriedades do objeto observável.

A interface Observable tem um mecanismo para adicionar e remover listeners, mas é preciso decidir quando as notificações serão enviadas. Para facilitar o desenvolvimento, a Data Binding Library oferece a classe BaseObservable, que implementa o mecanismo de registro de listener. A classe de dados que implementa BaseObservable é responsável por notificar quando as propriedades mudam. Para isso, atribua uma anotação Bindable ao getter e chame o método notifyPropertyChanged() no setter, conforme mostrado no exemplo a seguir:

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

    

A vinculação de dados gera uma classe chamada BR no pacote do módulo, que contém os códigos dos recursos usados para a vinculação de dados. A anotação Bindable gera uma entrada no arquivo da classe BR durante a compilação. Caso não seja possível mudar a classe base das classes de dados, a interface Observable pode ser implementada usando um objeto PropertyChangeRegistry para registrar e notificar os listeners de forma eficiente.

Outros recursos

Para saber mais sobre vinculação de dados, consulte os seguintes recursos adicionais.

Amostras

Codelabs

Postagens do blog