La observabilidad se refiere a 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.
Puedes usar cualquier objeto para la vinculación de datos, pero modificar el objeto no hace que la IU se actualice automáticamente. Puedes usar la vinculación de datos para darles a tus objetos de datos la capacidad de notificar a otros objetos (conocidos como objetos de escucha) cuando cambian sus datos. Hay tres tipos de clases observables: campos, colecciones y objetos.
Cuando uno de estos 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
Si tus clases solo tienen algunas propiedades, es posible que no valga la pena crear clases que implementen la interfaz Observable
. En este caso, puedes usar la clase genérica Observable
y las siguientes clases primitivas específicas para que los campos sean observables:
ObservableBoolean
ObservableByte
ObservableChar
ObservableShort
ObservableInt
ObservableLong
ObservableFloat
ObservableDouble
ObservableParcelable
Los campos observables son objetos observables independientes 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 el acceso a estas 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, puedes encontrar el mapa con las claves de string, como se muestra en el siguiente ejemplo:
<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, puedes acceder a la lista a través 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 sobre cambios de propiedad del objeto observable.
La interfaz Observable
tiene un mecanismo para agregar y quitar objetos de escucha, pero tú decides 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 llamada BR
en el paquete del módulo, que contiene los IDs 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 la clase base para las clases de datos no se puede cambiar, puedes implementar la interfaz Observable
con un objeto PropertyChangeRegistry
para registrar y notificar a los objetos de escucha de manera eficiente.
Objetos optimizados para ciclos de vida
Los diseños de tu app también pueden vincularse a fuentes de vinculación de datos que notifican automáticamente a la IU sobre cambios en los datos. De esta manera, tus vinculaciones están optimizadas para el ciclo de vida y solo se activan cuando la IU es visible en la pantalla.
La vinculación de datos admite StateFlow
y LiveData
. Si quieres obtener más información sobre el uso de LiveData
en la vinculación de datos, consulta Cómo usar LiveData para notificar a la IU los cambios en los datos.
Usa StateFlow
Si tu app usa Kotlin con corrutinas, puedes usar objetos StateFlow
como fuente de vinculación de datos. Para usar un objeto StateFlow
con tu clase de vinculación, especifica un propietario del ciclo de vida para definir el alcance del objeto StateFlow
. En el siguiente ejemplo, se especifica la actividad como propietario del ciclo de vida una vez que se crea una instancia de la clase de vinculación:
class ViewModelActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Inflate view and obtain an instance of the binding class.
val binding: UserBinding = DataBindingUtil.setContentView(this, R.layout.user)
// Specify the current activity as the lifecycle owner.
binding.lifecycleOwner = this
}
}
Como se describe en Cómo vincular vistas de diseño con componentes de arquitectura, la vinculación de datos funciona sin problemas con objetos ViewModel
. Puedes usar StateFlow
y ViewModel
juntos de la siguiente manera:
class ScheduleViewModel : ViewModel() {
private val _username = MutableStateFlow<String>("")
val username: StateFlow<String> = _username
init {
viewModelScope.launch {
_username.value = Repository.loadUserName()
}
}
}
En el diseño, asigna las propiedades y los métodos del objeto ViewModel
a las vistas correspondientes utilizando expresiones de vinculación, como se muestra en el siguiente ejemplo:
<TextView
android:id="@+id/name"
android:text="@{viewmodel.username}" />
La IU se actualiza automáticamente cada vez que cambia el valor del nombre del usuario.
Inhabilita la compatibilidad con StateFlow
Para las apps que utilizan Kotlin y AndroidX, la compatibilidad con StateFlow
se incluye automáticamente con la vinculación de datos. Eso significa que la dependencia de corrutinas se incluye automáticamente en tu app si aún no está disponible.
Para inhabilitar esta función, agrega lo siguiente a tu archivo build.gradle
:
Groovy
android { ... dataBinding { addKtx = false } }
Kotlin
android { ... dataBinding { addKtx = false } }
Como alternativa, puedes inhabilitar StateFlow
a nivel global en tu proyecto si agregas la siguiente línea al archivo gradle.properties
:
Groovy
android.defaults.databinding.addKtx = false
Kotlin
android.defaults.databinding.addKtx = false
Recursos adicionales
Si deseas obtener más información sobre la vinculación de datos, consulta los siguientes recursos adicionales:
Ejemplos
Codelabs
Entradas de blog
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Módulo de estado guardado para ViewModel
- Cómo vincular vistas de diseño con componentes de arquitectura
- Descripción general de la biblioteca de Paging