Modèle de conception MVVM Android

Dans ce tutoriel, nous discuterons et mettrons en œuvre le Modèle Architectural MVVM Android dans notre Application Android. Nous avons précédemment discuté du Modèle MVP Android.

Pourquoi avons-nous besoin de ces modèles ? Ajouter tout dans une seule Activité ou Fragment pourrait entraîner des problèmes lors des tests et du refactoring du code. Par conséquent, l’utilisation de la séparation du code et de l’architecture propre est recommandée.

Android MVVM

MVVM signifie Modèle, Vue, ViewModel.

  • Modèle: Il contient les données de l’application. Il ne peut pas communiquer directement avec la Vue. En général, il est recommandé d’exposer les données au ViewModel via des Observables.
  • Vue: Elle représente l’interface utilisateur de l’application dépourvue de toute logique d’application. Elle observe le ViewModel.
  • ViewModel: Il fait le lien entre le Modèle et la Vue. Il est responsable de la transformation des données du Modèle. Il fournit des flux de données à la Vue. Il utilise également des hooks ou des rappels pour mettre à jour la Vue. Il demandera les données au Modèle.

Le flux suivant illustre le modèle MVVM de base. En quoi cela diffère-t-il du MVP ?

  • Le ViewModel remplace le Présentateur dans la couche intermédiaire.
  • Le Présentateur détient des références vers la Vue. Le ViewModel non.
  • Le Présentateur met à jour la Vue en utilisant la manière classique (en déclenchant des méthodes).
  • Le ViewModel envoie des flux de données.
  • Le Présentateur et la Vue sont en relation un à un.
  • La Vue et le ViewModel sont en relation un à plusieurs.
  • Le ViewModel ne sait pas que la Vue écoute ses modifications.

Il existe deux façons d’implémenter MVVM sur Android :

  • La liaison de données
  • RXJava

Dans ce tutoriel, nous n’utiliserons que la liaison de données. La bibliothèque de liaison de données a été introduite par Google afin de lier directement les données dans la mise en page xml. Pour plus d’informations sur la liaison de données, consultez ce tutoriel. Nous créerons un exemple d’application de page de connexion simple qui demande des saisies utilisateur. Nous verrons comment le ViewModel notifie la Vue quand afficher un message Toast sans conserver de référence de la Vue.

Comment est-il possible de notifier une classe sans en avoir de référence ? Cela peut être fait de trois manières différentes :

  • En utilisant la liaison de données bidirectionnelle
  • En utilisant LiveData
  • En utilisant RxJava

La liaison de données bidirectionnelle

La liaison de données bidirectionnelle est une technique de liaison de vos objets à vos mises en page XML de telle sorte que l’objet et la mise en page puissent tous deux s’envoyer des données. Dans notre cas, le ViewModel peut envoyer des données à la mise en page et également observer les changements. Pour cela, nous avons besoin d’un BindingAdapter et d’un attribut personnalisé défini dans le XML. L’adaptateur de liaison écouterait les changements dans la propriété de l’attribut. Nous en apprendrons davantage sur la liaison de données bidirectionnelle à travers notre exemple ci-dessous.

Structure de projet d’exemple Android MVVM

Ajout de la bibliothèque de liaison de données

Ajoutez le code suivant au fichier build.gradle de votre application :

android {

    dataBinding {
        enabled = true
    }
}

Cela active la liaison de données dans votre application.

Ajout des dépendances

Ajoutez les dépendances suivantes dans votre fichier build.gradle :

implementation 'android.arch.lifecycle:extensions:1.1.0'

Modèle

Le modèle contiendrait l’e-mail et le mot de passe de l’utilisateur. La classe User.java suivante le fait :

package com.journaldev.androidmvvmbasics.model;


public class User {
    private String email;
    private String password;

    public User(String email, String password) {
        this.email = email;
        this.password = password;
    }

    public void setEmail(String email) {
        this.email = email;
    }


    public String getEmail() {
        return email;
    }

    public void setPassword(String password) {
        this.password = password;
    }


    public String getPassword() {
        return password;
    }


}

La liaison de données bidirectionnelle nous permet de lier des objets dans les mises en page XML de manière à ce que l’objet puisse envoyer des données à la mise en page, et vice versa. La syntaxe pour la liaison de données bidirectionnelle est @={variable}

Mise en page

Le code pour activity_main.xml est donné ci-dessous :

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:bind="https://schemas.android.com/tools">

    <data>

        <variable
            name="viewModel"
            type="com.journaldev.androidmvvmbasics.viewmodels.LoginViewModel" />
    </data>


    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_margin="8dp"
            android:orientation="vertical">

            <EditText
                android:id="@+id/inEmail"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Email"
                android:inputType="textEmailAddress"
                android:padding="8dp"
                android:text="@={viewModel.userEmail}" />


            <EditText
                android:id="@+id/inPassword"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Password"
                android:inputType="textPassword"
                android:padding="8dp"
                android:text="@={viewModel.userPassword}" />


            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:onClick="@{()-> viewModel.onLoginClicked()}"
                android:text="LOGIN"
                bind:toastMessage="@{viewModel.toastMessage}" />


        </LinearLayout>

    </ScrollView>

</layout>

La liaison de données nécessite de définir la balise de mise en page en haut. Ici, notre ViewModel lie les données à la Vue. ()-> viewModel.onLoginClicked() invoque le lambda du gestionnaire de clic de bouton défini dans notre ViewModel. L’EditText met à jour les valeurs dans le modèle (via ViewModel). bind:toastMessage="@{viewModel.toastMessage}" est un attribut personnalisé que nous avons créé pour la liaison de données bidirectionnelle. En fonction des changements dans toastMessage dans le ViewModel, l’BindingAdapter serait déclenché dans la Vue.

ViewModel

Le code pour LoginViewModel.java est donné ci-dessous :

package com.journaldev.androidmvvmbasics.viewmodels;

import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.text.TextUtils;
import android.util.Patterns;

import com.android.databinding.library.baseAdapters.BR;
import com.journaldev.androidmvvmbasics.model.User;

public class LoginViewModel extends BaseObservable {
    private User user;


    private String successMessage = "Login was successful";
    private String errorMessage = "Email or Password not valid";

    @Bindable
    private String toastMessage = null;


    public String getToastMessage() {
        return toastMessage;
    }


    private void setToastMessage(String toastMessage) {

        this.toastMessage = toastMessage;
        notifyPropertyChanged(BR.toastMessage);
    }


    public void setUserEmail(String email) {
        user.setEmail(email);
        notifyPropertyChanged(BR.userEmail);
    }

    @Bindable
    public String getUserEmail() {
        return user.getEmail();
    }

    @Bindable
    public String getUserPassword() {
        return user.getPassword();
    }

    public void setUserPassword(String password) {
        user.setPassword(password);
        notifyPropertyChanged(BR.userPassword);
    }

    public LoginViewModel() {
        user = new User("","");
    }

    public void onLoginClicked() {
        if (isInputDataValid())
            setToastMessage(successMessage);
        else
            setToastMessage(errorMessage);
    }

    public boolean isInputDataValid() {
        return !TextUtils.isEmpty(getUserEmail()) && Patterns.EMAIL_ADDRESS.matcher(getUserEmail()).matches() && getUserPassword().length() > 5;
    }
}

Les méthodes appelées dans la mise en page sont implémentées dans le code ci-dessus avec la même signature. Si le pendant XML de la méthode n’existe pas, nous devons changer l’attribut en app:. La classe ci-dessus peut également étendre ViewModel. Mais nous avons besoin de BaseObservable car elle convertit les données en flux et notifie lorsque la propriété toastMessage est modifiée. Nous devons définir le getter et le setter pour l’attribut personnalisé toastMessage défini dans le XML. À l’intérieur du setter, nous notifions l’observateur (qui sera la Vue dans notre application) que les données ont changé. La Vue (notre activité) peut définir l’action appropriée.

La classe BR est générée automatiquement à partir de la liaison de données lorsque vous reconstruisez le projet

Le code de la classe MainActivity.java est donné ci-dessous:

package com.journaldev.androidmvvmbasics.views;


import android.databinding.BindingAdapter;
import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;


import com.journaldev.androidmvvmbasics.R;
import com.journaldev.androidmvvmbasics.databinding.ActivityMainBinding;
import com.journaldev.androidmvvmbasics.viewmodels.LoginViewModel;


public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        activityMainBinding.setViewModel(new LoginViewModel());
        activityMainBinding.executePendingBindings();

    }

    @BindingAdapter({"toastMessage"})
    public static void runMe(View view, String message) {
        if (message != null)
            Toast.makeText(view.getContext(), message, Toast.LENGTH_SHORT).show();
    }
}

Grâce à la liaison de données, la classe ActivityMainBinding est générée automatiquement à partir de la mise en page. La méthode @BindingAdapter est déclenchée chaque fois que l’attribut toastMessage défini sur le bouton est modifié. Elle doit utiliser le même attribut que celui défini dans le XML et dans le ViewModel. Ainsi, dans l’application ci-dessus, le ViewModel met à jour le Modèle en écoutant les changements dans la Vue. De plus, le Modèle peut mettre à jour la vue via le ViewModel en utilisant notifyPropertyChanged. Le résultat de l’application ci-dessus en action est donné ci-dessous: Cela marque la fin de ce tutoriel sur Android MVVM utilisant la liaison de données. Vous pouvez télécharger le projet via le lien donné ci-dessous.

AndroidMVVMBasics

Lien vers le projet Github

Source:
https://www.digitalocean.com/community/tutorials/android-mvvm-design-pattern