Lier les vues de disposition aux composants de l'architecture

La bibliothèque AndroidX inclut les composants d'architecture, qui vous permettent de concevoir des applications robustes, testables et faciles à gérer. La bibliothèque Data Binding fonctionne parfaitement avec les composants d'architecture pour simplifier le développement de votre UI. Les mises en page de votre application peuvent être associées aux données des composants d'architecture, ce qui vous aide à gérer le cycle de vie du contrôleur d'interface utilisateur et à l'informer des modifications apportées aux données.

Cette page explique comment intégrer les composants d'architecture à votre application pour tirer le meilleur parti de la bibliothèque Data Binding.

Utiliser LiveData pour informer l'UI des modifications de données

Vous pouvez utiliser des objets LiveData en tant que source de liaison de données pour avertir automatiquement l'interface utilisateur des modifications apportées aux données. Pour en savoir plus sur ce composant d'architecture, consultez la présentation de LiveData.

Contrairement aux objets qui implémentent des Observable, tels que des champs observables, les objets LiveData connaissent le cycle de vie des observateurs abonnés aux modifications des données. Ces connaissances offrent de nombreux avantages, qui sont expliqués dans la section Avantages de l'utilisation de LiveData. Dans Android Studio version 3.1 ou ultérieure, vous pouvez remplacer les champs observables par des objets LiveData dans votre code de liaison de données.

Pour utiliser un objet LiveData avec votre classe de liaison, vous devez spécifier un propriétaire de cycle de vie afin de définir le champ d'application de l'objet LiveData. L'exemple suivant spécifie l'activité en tant que propriétaire du cycle de vie après l'instanciation de la classe de liaison:

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

Vous pouvez utiliser un composant ViewModel, comme expliqué dans la section suivante, pour lier les données à la mise en page. Dans le composant ViewModel, vous pouvez utiliser l'objet LiveData pour transformer les données ou fusionner plusieurs sources de données. L'exemple suivant montre comment transformer les données dans 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);
    }
}

Utiliser ViewModel pour gérer les données liées à l'interface utilisateur

La bibliothèque Data Binding fonctionne parfaitement avec les composants ViewModel. ViewModel expose les données que la mise en page observe et réagit à ses modifications. L'utilisation de composants ViewModel avec la bibliothèque Data Binding vous permet de déplacer la logique d'UI des mises en page vers les composants, qui sont plus faciles à tester. La bibliothèque de liaison de données garantit que les vues sont liées ou dissociées de la source de données si nécessaire. La majeure partie du travail restant consiste à s'assurer que vous exposez les bonnes données. Pour en savoir plus sur ce composant d'architecture, consultez la présentation de ViewModel.

Pour utiliser le composant ViewModel avec la bibliothèque Data Binding, vous devez instancier votre composant (qui hérite de la classe ViewModel), obtenir une instance de votre classe de liaison et attribuer votre composant ViewModel à une propriété de la classe de liaison. L'exemple suivant montre comment utiliser le composant avec la bibliothèque:

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

Dans votre mise en page, attribuez les propriétés et les méthodes de votre composant ViewModel aux vues correspondantes à l'aide d'expressions de liaison, comme illustré dans l'exemple suivant:

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

Utiliser un ViewModel observable pour mieux contrôler les adaptateurs de liaison

Vous pouvez utiliser un composant ViewModel qui implémente l'interface Observable pour avertir les autres composants d'application des modifications apportées aux données, de la même manière que vous utiliseriez un objet LiveData.

Dans certains cas, il peut être préférable d'utiliser un composant ViewModel qui implémente l'interface Observable plutôt que d'utiliser des objets LiveData, même si vous perdez les fonctionnalités de gestion du cycle de vie de LiveData. L'utilisation d'un composant ViewModel qui implémente Observable vous permet de mieux contrôler les adaptateurs de liaison dans votre application. Par exemple, ce modèle vous permet de mieux contrôler les notifications lorsque les données changent. Il vous permet également de spécifier une méthode personnalisée pour définir la valeur d'un attribut dans la liaison de données bidirectionnelle.

Pour implémenter un composant ViewModel observable, vous devez créer une classe qui hérite de la classe ViewModel et implémente l'interface Observable. Vous pouvez fournir une logique personnalisée lorsqu'un observateur s'abonne ou se désabonne aux notifications à l'aide des méthodes addOnPropertyChangedCallback() et removeOnPropertyChangedCallback(). Vous pouvez également fournir une logique personnalisée qui s'exécute lorsque les propriétés changent dans la méthode notifyPropertyChanged(). L'exemple de code suivant montre comment implémenter 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);
    }
}

Ressources supplémentaires

Pour en savoir plus sur la liaison de données, consultez les ressources supplémentaires suivantes.