Cómo vincular vistas de diseño con componentes de arquitectura

La biblioteca de AndroidX incluye los componentes de la arquitectura, que puedes usar para diseñar apps sólidas, aptas para pruebas y mantenibles. La biblioteca de vinculación de datos funciona sin problemas con los componentes de la arquitectura para simplificar aún más el desarrollo de tu IU. Los diseños de tu app se pueden vincular a los datos de los componentes de la arquitectura, lo que te ayuda a administrar el ciclo de vida del controlador de IU y notificar a la IU sobre los cambios en los datos.

En este documento, se muestra cómo incorporar los componentes de la arquitectura a tu app para aprovechar al máximo la biblioteca de vinculación de datos.

Usa LiveData para notificar a la IU los cambios en los datos

Puedes usar objetos LiveData como fuente de vinculación de datos para notificar automáticamente a la IU sobre cambios en los datos. Para obtener más información sobre este componente de la arquitectura, consulta la descripción general de LiveData.

A diferencia de los objetos que implementan Observable, como los campos observables, los objetos LiveData conocen el ciclo de vida de los observadores suscritos a los cambios de datos. Este conocimiento ofrece muchos beneficios, que se explican en Ventajas de usar LiveData. En Android Studio 3.1 y versiones posteriores, puedes reemplazar los campos observables por objetos LiveData en tu código de vinculación de datos.

Para usar un objeto LiveData con tu clase de vinculación, debes especificar un propietario del ciclo de vida para definir el alcance del objeto LiveData. En el siguiente ejemplo, se especifica la actividad como el propietario del ciclo de vida después de que se crea una instancia de la clase de vinculación:

Kotlin

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.setLifecycleOwner(this)
    }
}

Java

class ViewModelActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Inflate view and obtain an instance of the binding class.
        UserBinding binding = DataBindingUtil.setContentView(this, R.layout.user);

        // Specify the current activity as the lifecycle owner.
        binding.setLifecycleOwner(this);
    }
}

Puedes usar un componente ViewModel, como se explica en la siguiente sección, para vincular los datos al diseño. En el componente ViewModel, puedes usar el objeto LiveData para transformar los datos o combinar varias fuentes de datos. En el siguiente ejemplo, se muestra cómo transformar los datos en ViewModel:

Kotlin

class ScheduleViewModel : ViewModel() {
    val userName: LiveData<String>

    init {
        val result = Repository.userName
        userName = Transformations.map(result) { result -> result.value }
    }
}

Java

class ScheduleViewModel extends ViewModel {
    LiveData<String> username;

    public ScheduleViewModel() {
        String result = Repository.userName;
        userName = Transformations.map(result, result -> result.value);
    }
}

Usa ViewModel para administrar datos relacionados con la IU

La biblioteca de vinculación de datos funciona sin problemas con los componentes de ViewModel. ViewModel expone los datos que observa el diseño y reacciona a sus cambios. El uso de componentes de ViewModel con la biblioteca de vinculación de datos te permite mover la lógica de la IU fuera de los diseños y hacia los componentes, que son más fáciles de probar. La biblioteca de vinculación de datos garantiza que las vistas se vinculen y desvinculen de la fuente de datos cuando sea necesario. La mayor parte del trabajo restante consiste en asegurarte de exponer los datos correctos. Para obtener más información sobre este componente de la arquitectura, consulta la descripción general de ViewModel.

Para usar el componente ViewModel con la biblioteca de vinculación de datos, debes crear una instancia de tu componente, que hereda de la clase ViewModel, obtener una instancia de tu clase de vinculación y asignar tu componente ViewModel a una propiedad en la clase de vinculación. En el siguiente ejemplo, se muestra cómo usar el componente con la biblioteca:

Kotlin

class ViewModelActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // Obtain the ViewModel component.
        val userModel: UserModel by viewModels()

        // Inflate view and obtain an instance of the binding class.
        val binding: UserBinding = DataBindingUtil.setContentView(this, R.layout.user)

        // Assign the component to a property in the binding class.
        binding.viewmodel = userModel
    }
}

Java

class ViewModelActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Obtain the ViewModel component.
        UserModel userModel = new ViewModelProvider(this).get(UserModel.class);

        // Inflate view and obtain an instance of the binding class.
        UserBinding binding = DataBindingUtil.setContentView(this, R.layout.user);

        // Assign the component to a property in the binding class.
        binding.viewmodel = userModel;
    }
}

En tu diseño, asigna las propiedades y los métodos de tu componente ViewModel a las vistas correspondientes con expresiones de vinculación, como se muestra en el siguiente ejemplo:

<CheckBox
    android:id="@+id/rememberMeCheckBox"
    android:checked="@{viewmodel.rememberMe}"
    android:onCheckedChanged="@{() -> viewmodel.rememberMeChanged()}" />

Utiliza un ViewModel observable para tener más control sobre los adaptadores de vinculación

Puedes usar un componente ViewModel que implemente la interfaz Observable para notificar a otros componentes de la app sobre los cambios en los datos, de manera similar a como usarías un objeto LiveData.

Hay situaciones en las que tal vez prefieras usar un componente de ViewModel que implemente la interfaz de Observable en lugar de usar objetos LiveData, incluso si pierdes las capacidades de administración del ciclo de vida de LiveData. Usar un componente ViewModel que implemente Observable te brinda más control sobre los adaptadores de vinculación de tu app. Por ejemplo, este patrón te brinda más control sobre las notificaciones cuando cambian los datos. También te permite especificar un método personalizado para establecer el valor de un atributo en la vinculación de datos bidireccional.

Para implementar un componente ViewModel observable, debes crear una clase que herede de la clase ViewModel y que implemente la interfaz Observable. Puedes proporcionar lógica personalizada cuando un observador se suscribe o cancela la suscripción a las notificaciones con los métodos addOnPropertyChangedCallback() y removeOnPropertyChangedCallback(). También puedes proporcionar una lógica personalizada que se ejecute cuando cambien las propiedades en el método notifyPropertyChanged(). En el siguiente ejemplo de código, se muestra cómo implementar un ViewModel observable:

Kotlin

/**
 * A ViewModel that is also an Observable,
 * to be used with the Data Binding Library.
 */
open class ObservableViewModel : ViewModel(), Observable {
    private val callbacks: PropertyChangeRegistry = PropertyChangeRegistry()

    override fun addOnPropertyChangedCallback(
            callback: Observable.OnPropertyChangedCallback) {
        callbacks.add(callback)
    }

    override fun removeOnPropertyChangedCallback(
            callback: Observable.OnPropertyChangedCallback) {
        callbacks.remove(callback)
    }

    /**
     * Notifies observers that all properties of this instance have changed.
     */
    fun notifyChange() {
        callbacks.notifyCallbacks(this, 0, null)
    }

    /**
     * Notifies observers that a specific property has changed. The getter for the
     * property that changes must be marked with the @Bindable annotation to
     * generate a field in the BR class to be used as the fieldId parameter.
     *
     * @param fieldId The generated BR id for the Bindable field.
     */
    fun notifyPropertyChanged(fieldId: Int) {
        callbacks.notifyCallbacks(this, fieldId, null)
    }
}

Java

/**
 * A ViewModel that is also an Observable,
 * to be used with the Data Binding Library.
 */
class ObservableViewModel extends ViewModel implements Observable {
    private PropertyChangeRegistry callbacks = new PropertyChangeRegistry();

    @Override
    protected void addOnPropertyChangedCallback(
            Observable.OnPropertyChangedCallback callback) {
        callbacks.add(callback);
    }

    @Override
    protected void removeOnPropertyChangedCallback(
            Observable.OnPropertyChangedCallback callback) {
        callbacks.remove(callback);
    }

    /**
     * Notifies observers that all properties of this instance have changed.
     */
    void notifyChange() {
        callbacks.notifyCallbacks(this, 0, null);
    }

    /**
     * Notifies observers that a specific property has changed. The getter for the
     * property that changes must be marked with the @Bindable annotation to
     * generate a field in the BR class to be used as the fieldId parameter.
     *
     * @param fieldId The generated BR id for the Bindable field.
     */
    void notifyPropertyChanged(int fieldId) {
        callbacks.notifyCallbacks(this, fieldId, null);
    }
}

Recursos adicionales

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