Android MVP Architecture

La flexibilité d’Android vous permet de concevoir des applications de la manière qui vous convient le mieux. Elle offre aux développeurs une puissance considérable pour créer d’excellentes applications, mais aussi des difficultés dues à la différence d’approche. Par conséquent, la nécessité d’utiliser un modèle d’architecture est évidente. Le modèle MVP (Model View Presenter) est un dérivé du célèbre MVC (Model View Controller), qui gagne en popularité et en importance dans le développement d’applications Android. Nous nous sommes fixé pour objectif de déterminer les principales raisons pour lesquelles nous pouvons et devrions utiliser ce modèle architectural.

Tout d’abord, nous devons définir la différence avec le modèle MVC, et nous pouvons la montrer schématiquement :

différences entre MVP et MVC

Les principales différences entre MVP et MVC sont :

  • View est séparé de Model, Presenter est un intermédiaire entre View et Model ;
  • plus facile de créer des tests Unitaires ;
  • généralement, nous pouvons utiliser plusieurs Presenters pour des Views complexes.

Examinons chaque point en détail et soulignons ses principaux avantages :

En suivant l’un des concepts principaux de la Clean Architecture, “Diviser pour régner”, le modèle MVP permet de séparer la couche de présentation de la logique. Dans ce cas, les fonctions principales de chaque élément sont :

  1. La View. L’Activity ou le fragment sera privé de traitement de données et se contentera d’afficher. Par exemple, un fragment implémente ici une certaine interface avec des fonctions :
    
    public interfece ListInterface {
        void showError();
        void showItems(List someItems );
    }
    
  2. Le Presenter prend entièrement en charge la logique métier. Les requêtes pour obtenir des données d’un serveur ou d’une base de données (communication avec le modèle) sont implémentées ici. Après réception des données, tout le traitement des données est également effectué par le presenter. Après traitement, les informations sont transmises à la view via la même interface :
    //Si le résultat est une erreurgetView.showError();
    //Si le résultat est un succès - nous passons les donnéesgetView.showItems(someitems);
    
  3. Ce processus est illustré sur le schéma ci-dessous :
  4. Couverture des tests unitaires. L’avantage principal est la possibilité de tester chaque partie séparément. Nous pouvons également choisir la technologie et l’approche des tests unitaires.
    • Pour la view, il est pratique d’utiliser Mockito, Robolectric avec les annotations @Before, @Test, @After. Exemple :
      @Beforepublic void setUp() {
          TestHelper.getTestClassInjector() .inject(this);
          Assert.assertTrue(TestHelper.getBaseComponent().getLocalDataCache() instanceof MockLocalDataCache);
          Assert.assertTrue(TestHelper.getBaseComponent().getRetrofit() instanceof MockRetrofit);
          Assert.assertTrue(TestHelper.getBaseComponent().getOkHTTP() instanceof MockOkHTTP);
      }
      @Testpublic void testWebPage() {
          viewModel.loadWebPage(SOME_URL).toBlocking().forEach(s -> {
              Assert.assertTrue(s.contains(MockRetrofit.MOCKED_STRING)& & s.contains(SOME_URL));
          });
      }
      
    • Nous testerons le presenter de la même manière que nous avons testé le modèle, avec un simple test JUnit. Cependant, cette fois-ci, nous fournirons une view modifiée pour nous assurer que le presenter est correctement lié à la view. Notre presenter recevra la view et obtiendra les données du modèle pour les afficher dans la view.
      @Beforepublic void setUp() throws Exception {
          MockitoAnnotations.initMocks(this);
          when(interactor.getUserProfile()).thenReturn(Observable.just(newUserProfile()));
          presenter = new ProfilePresenter(interactor);
          presenter.attachView(view);
      }
      @Testpublic void testDisplayCalled() {
          verify(interactor).getUserProfile();
          verify(view).display(any());
      }
      public void fetchAndDisplay() {
          interactor.getUserProfile().subscribe(userProfile ->view.display(userProfile));
      }
      
  5. Indépendance du cycle de vie de l’application. Un exemple concret est lorsque nous effectuons une requête et qu’un utilisateur ferme l’application, ou change l’orientation de l’écran. Notre requête n’est pas liée à l’activité et n’échoue pas, les données peuvent être obtenues et affichées lorsque la view change d’état à inResume() à nouveau. Une vérification d’activité nulle est nécessaire :
    if (getActivity != null) {// travail avec l'interface utilisateur…getView.showResult(result);}
    
  6. Capacité à utiliser un presenter pour plusieurs views. Lorsque nous utilisons la même logique pour plusieurs écrans, par exemple, la réception et la mise à jour d’une liste de messages, nous pouvons utiliser un seul presenter contenant toute la logique pour ces deux views. Par exemple, il existe un presenter et 2 fragments de réception de messages :
    • MessageUpdatePresenter ;
    • SentMessagesFragment implémente MessageUpdatePresenter ;
    • DraftsMessagesFragment implémente MessageUpdatePresenter ;

    Dans chaque fragment, nous implémentons l’interface MessageUpdatePresenter, qu’il s’agisse de la méthode showMessages(List <Message> messages).
    utilisation d'un presenter par plusieurs views
    Lors du développement d’une application Android pour une grande entreprise de marketing allemande, nous avons été mis au défi de créer l’architecture d’une application complexe et multifonctionnelle. Après discussion avec l’équipe, nous avons opté pour l’utilisation du MVP, ce qui nous a permis de :

    • séparer la logique métier de la présentation, de structurer le tout et de répartir la charge ;
    • d’augmenter considérablement la qualité du produit grâce à une couverture de tests pratique, beaucoup plus facile et rapide à écrire ;
    • de réduire le nombre de répétitions dans le code, puisque le presenter peut être réutilisé.

 

À propos de Redwerk

Redwerk opère dans le domaine du développement d’applications mobiles depuis 2005. Au cours des treize dernières années, nous avons développé avec succès de nombreuses applications iOS et Android qui ont rassemblé des centaines de milliers d’utilisateurs dans le monde entier. Nous proposons le développement complet d’applications mobiles, de l’idée au lancement, et garantissons des solutions de haute qualité à nos clients.