Lorsque j'ai commencé mon parcours en tant que développeur Android, les mots « Architecture d'applications mobiles » m'ont profondément perplexe, Google et les articles sur Habré m'ont plongé dans une dépression encore plus grande - je regarde le livre et je ne vois rien. Je pense que si vous lisez cet article, vous avez déjà étudié cette image plus d'une fois et essayé de comprendre ce qui se passe : le problème de la compréhension de l'approche architecturale dans le développement mobile, à mon avis, réside dans l'abstraction de l'architecture elle-même. Chaque développeur a sa propre vision de la manière de mettre en œuvre correctement tel ou tel modèle. Des exemples plus ou moins décents de mise en œuvre de MVP ont été trouvés dans le secteur anglophone d'Internet, ce qui n'est pas surprenant. Regardons brièvement ce que c'est et passons à un exemple. Modèle - niveau de données. Je n'aime pas utiliser le terme « logique métier », donc dans mes applications je l'appelle Repository et il communique avec la base de données et le réseau. Vue — niveau d'affichage. Ce sera Activity , Fragment ou Custom View si vous n'aimez pas danser avec un tambourin et interagir avec le cycle de vie. Permettez-moi de vous rappeler qu'au départ, toutes les applications Android sont subordonnées à la structure MVC , où le contrôleur est une activité ou un fragment . Presenter est une couche entre View et Model. View transmet les événements qui lui surviennent, le présentateur les traite, si nécessaire, accède au Modèle et renvoie les données à la View pour le rendu. En ce qui concerne Android et un exemple spécifique, je soulignerai la partie importante : le contrat. Il s'agit de l'interface qui décrit toutes les interactions entre les composants ci-dessus. Pour résumer la partie théorique :
- View connaît Presenter ;
- Le présentateur connaît la vue et le modèle (référentiel) ;
- Modèle seul ;
- Le contrat régit les interactions entre eux.
MainContract
:
public interface MainContract {
interface View {
void showText();
}
interface Presenter {
void onButtonWasClicked();
void onDestroy();
}
interface Repository {
String loadMessage();
}
}
Pour l’instant, nous mettons simplement en avant les 3 composants de notre future application et ce qu’ils feront. Nous décrirons ensuite le référentiel :
public class MainRepository implements MainContract.Repository {
private static final String TAG = "MainRepository";
@Override
public String loadMessage() {
Log.d(TAG, "loadMessage()");
/** Здесь обращаемся к БД or сети.
* Я специально ничего не пишу, чтобы не загромождать пример
* DBHelper'ами и прочими не относяшимеся к теме an objectми.
* Поэтому я буду возвращать строку Сосисочная =)
*/
return "Сосисочная у Лёхи»;
}
}
Tout est clair avec, il suffit de charger et de décharger des données. La prochaine étape est le présentateur :
public class MainPresenter implements MainContract.Presenter {
private static final String TAG = "MainPresenter";
//Компоненты MVP applications
private MainContract.View mView;
private MainContract.Repository mRepository;
//Сообщение
private String message;
//Обрати внимание на аргументы конструктора - мы передаем экземпляр View, а Repository просто создаём конструктором.
public MainPresenter(MainContract.View mView) {
this.mView = mView;
this.mRepository = new MainRepository();
Log.d(TAG, "Constructor");
}
//View сообщает, что кнопка была нажата
@Override
public void onButtonWasClicked() {
message = mRepository.loadMessage();
mView.showText(message);
Log.d(TAG, "onButtonWasClicked()");
}
@Override
public void onDestroy() {
/**
* Если бы мы работали например с RxJava, в этом классе стоило бы отписываться от подписок
* Кроме того, при работе с другими методами асинхронного андроида,здесь мы боремся с утечкой контекста
*/
Log.d(TAG, "onDestroy()");
}
}
Vous souvenez-vous que j'ai écrit sur la danse avec un tambourin et le cycle de la vie ? Le Presenter vit aussi longtemps que sa View, lors du développement de scénarios utilisateur complexes, je vous conseille de dupliquer tous les rappels View dans le Presenter et de les appeler aux moments appropriés, en dupliquant le cycle de vie Activité/Fragment, afin de comprendre à temps quels sont les besoins en finir avec les données qui traînent actuellement dans « l’intercalaire ». Et enfin, voir :
public class MainActivity extends AppCompatActivity implements MainContract.View {
private static final String TAG = "MainActivity";
private MainContract.Presenter mPresenter;
private Button mButton;
private TextView myTv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Создаём Presenter и в аргументе передаём ему this - эта Activity расширяет интерфейс MainContract.View
mPresenter = new MainPresenter(this);
myTv = (TextView) findViewById(R.id.text_view);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.onButtonWasClicked();
}
});
Log.d(TAG, "onCreate()");
}
@Override
public void showText(String message) {
myTv.setText(message);
Log.d(TAG, "showMessage()");
}
//Вызываем у Presenter метод onDestroy, чтобы избежать утечек контекста и прочих неприятностей.
@Override
public void onDestroy() {
super.onDestroy();
mPresenter.onDestroy();
Log.d(TAG, "onDestroy()");
}
}
Que se passe-t-il?
- L'activité, également connue sous le nom de View,
onCreate()
crée une instance Presenter dans une méthode et se transmet à son constructeur. - Lorsqu'un présentateur est créé, il reçoit explicitement une vue et crée une instance de référentiel (d'ailleurs, il peut devenir un Singleton)
- Lorsqu'un bouton est enfoncé, la vue frappe le présentateur et dit : « Le bouton a été enfoncé. »
- Le présentateur se tourne vers Repository : "Téléchargez cette merde pour moi."
- Le référentiel charge et livre les « trucs » au présentateur.
- Le présentateur se tourne vers View : « Voici les données pour vous, dessinez-les »
GO TO FULL VERSION