web-dev-qa-db-fra.com

Android MVP Activité ouverte du présentateur, anti-modèle?

Serait-ce un anti-motif si à partir d'un calque Presenter j'ouvre un Activity?

Si oui, dois-je gérer la navigation de l'application à partir de la couche d'affichage?

32
Jose M Lechon

Oui, c'est un modèle anti-mvp. Basé sur vue passive dans MVP, vous avez perdu votre testabilité, car vous n'avez pas à gérer le cadre Android dans votre présentateur).

Il est donc préférable de gérer la navigation de l'application à partir de la couche d'affichage.

class MyPresenter {
    MyPresenter.View view;

    void backButtonClicked() {
        view.navigateToHomeScreen();
    }

    public interface View {
        void navigateToHomeScreen();
    }
}

class MyActivity extends Activity implements MyPresenter.View {
    @Override
    void navigateToHomeScreen() {
        startActivity(...)
    }

    @OnClick(R.id.my_button)
    void onClick() {
        presenter.backButtonClicked();
    }
} 

Un autre avantage de cette manière est qu'il sera facile de remplacer l'activité par un fragment ou une vue.

Modifier 1:

Morgwai a dit que cette façon rompra la séparation des préoccupations et de la responsabilité unique, mais vous ne pouvez pas avoir une seule responsabilité partout. Parfois, vous devez le violer. Voici un exemple de Google pour MVP:

TaskDetailPresenter appelle ShowEditTask qui est chargé d'ouvrir un nouveau Activity à l'intérieur de TaskDetailFragment.

Mais vous pouvez également utiliser CommandPattern qui est une meilleure approche

interface NavigationCommand {
    void navigate();
}

Ainsi, Presenter l'utilisera quand il en aura besoin.

37
Saeed Masoumi

Comme je l'ai écrit dans mon commentaire à réponse acceptée , je pense que la gestion de la navigation à partir de la couche de vue est une rupture claire de la règle de séparation des préoccupations: les vues doivent contenir UNIQUEMENT des méthodes pour mettre à jour l'écran actuel de l'interface utilisateur.

Le problème provient des classes Android de conception de plate-forme comme Activity et Fragment contiennent les deux méthodes pour fonctionner sur l'écran de l'interface utilisateur et pour envoyer des objets d'intention qui démarrent d'autres activités comme startActivity.

Un moyen propre de résoudre ce problème serait de créer une interface Navigator qui contiendrait des méthodes liées à la navigation, de les implémenter et de les injecter dans les présentateurs. De cette façon, du moins du point de vue des présentateurs, la navigation et la manipulation de l'interface utilisateur seraient séparées. Cela peut cependant sembler étrange du point de vue des activités: maintenant, ils implémentent souvent les deux interfaces (Navigator et View) et transmettent leur référence 2 fois au présentateur. Si, pour cette raison, vous décidez de gérer la navigation à partir de votre couche de vue, gardez au moins les méthodes de navigation distinctes de celles de manipulation de l'interface utilisateur: n'effectuez jamais la navigation et la manipulation d'interface utilisateur dans la même méthode.

9
morgwai

À mon avis, il serait préférable d'ouvrir une activité à partir de la couche d'affichage. Je préfère que le présentateur connaisse le moins possible l'activité.

S'il y a une condition de l'activité à démarrer, vous pouvez utiliser quelque chose comme ceci:

public class Presenter {

    private ViewsPresentation mViewsPresentation;

    public void someButtonClicked() {
        if (/*some condition*/) {
            mViewsPresentation.startFirstActivity();
        } else {
            mViewsPresentation.startSecondActivity();
        }
    }

    public interface ViewsPresentation {
        void startFirstActivity();
        void startSecondActivity();
    }

}
6
Alexander