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, que puedan someterse a pruebas y admitan mantenimiento. La biblioteca de vinculación de datos funciona a la perfección con los componentes de la arquitectura para simplificar aún más el desarrollo de la IU. Los diseños de tu app pueden vincularse a los datos en los componentes de la arquitectura, lo que te ayuda a administrar el ciclo de vida del controlador de IU y a notificar a la IU los cambios en los datos.

En esta página, se muestra cómo incorporar los componentes de la arquitectura en tu app para aprovechar al máximo el uso de 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 habilita muchos beneficios, que se explican en Las ventajas de usar LiveData. En Android Studio 3.1 y versiones posteriores, puedes reemplazar campos observables con 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 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 el ViewModel:

Kotlin

class ScheduleViewModel : ViewModel() {
    val userName: LiveData

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

Java

class ScheduleViewModel extends ViewModel {
    LiveData 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 a la perfección con los componentes ViewModel. ViewModel expone los datos que el diseño observa y reacciona a sus cambios. El uso de componentes 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 estén vinculadas y desvinculadas de la fuente de datos cuando sea necesario. La mayor parte del trabajo restante consiste en asegurarse 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 la clase de vinculación y asignar el 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 el diseño, asigna las propiedades y los métodos del componente ViewModel a las vistas correspondientes utilizando 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 cambios en los datos, de manera similar a como usarías un objeto LiveData.

Hay situaciones en las que quizás prefieras usar un componente ViewModel que implemente la interfaz Observable en lugar de usar objetos LiveData, incluso si pierdes las capacidades de administración del ciclo de vida de LiveData. El uso de un componente ViewModel que implemente Observable te da más control sobre los adaptadores de vinculación en tu app. Por ejemplo, este patrón te brinda mayor 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 se herede de la clase ViewModel e implemente la interfaz Observable. Puedes proporcionar una lógica personalizada cuando un observador se suscribe a las notificaciones o anula la suscripción a ellas 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.