MVP Pattern in Android (with Examples)

MVP Pattern in Android (with Examples)

Recently, I have been using my spare time at work to learn various network open source projects. I am also building an Android open source framework. I hope to give a summary of the knowledge.

Here we use a simple application to explain MVP. There are also many github source codes at the end, which are all classic examples that you can learn from.

(1). Introduction to MVP Model

I believe everyone is familiar with MVC: M-Model, V-View, C-Controller. MVP is an evolved version of MVC, so the corresponding meaning of MVP is: M-Model, V-View, P-Presenter. From the combination of MVC and MVP, Controller/Presenter plays the role of logical control processing in MVC/MVP, and plays the role of controlling various business processes. The biggest difference between MVP and MVC is that M and V are not directly related, that is, there is no direct relationship between Model and View. The Presenter layer is between the two, which is responsible for regulating the indirect interaction between View and Model. In Android, it is very important that the operation of UI basically needs to be performed asynchronously, that is, the UI can only be operated in the MainThread, so it is reasonable to cut off and separate View and Model. In addition, the interaction between Presenter and View and Model can further achieve loose coupling by using interfaces to define interactive operations, and unit testing can be more conveniently performed through interfaces. So there is this picture (comparison between MVP and MVC)

Comparison between MVP and MVC

In fact, the most obvious difference is that MVC allows Model and View to interact, while in MVP, it is obvious that the interaction between Model and View is completed by Presenter. Another point is that the interaction between Presenter and View is through the interface (which will be reflected in the code).

(2) Application of MVP model

2.1 Model layer description and specific code

Provide the data we want to display in the view layer and the implementation of specific login business logic processing,

  1. package com.nsu.edu.androidmvpdemo.login;
  2.  
  3.   
  4.  
  5. /**
  6.  
  7. * Created by Anthony on 2016/2/15.
  8.  
  9. * Class Note: The interface for simulating login operations. The implementation class is LoginModelImpl. It is equivalent to the Model layer in the MVP mode.
  10.  
  11. */
  12.  
  13. public interface LoginModel {
  14.  
  15. void login(String username, String password , OnLoginFinishedListener listener);
  16.  
  17. }
  18.  
  19.  
  20. package com.nsu.edu.androidmvpdemo.login;
  21.  
  22.   
  23.  
  24. import android.os.Handler;
  25.  
  26. import android.text.TextUtils;
  27.  
  28. /**
  29.  
  30. * Created by Anthony on 2016/2/15.
  31.  
  32. * Class Note: Delayed simulation login (2s), if the name or password is empty, the login fails, otherwise the login is successful
  33.  
  34. */
  35.  
  36. public class LoginModelImpl implements LoginModel {
  37.  
  38.   
  39.  
  40. @Override
  41.  
  42. public void login(final String username, final String password , final OnLoginFinishedListener listener) {
  43.  
  44.   
  45.  
  46. new Handler().postDelayed(new Runnable() {
  47.  
  48. @Override public void run() {
  49.  
  50. boolean error = false ;
  51.  
  52. if (TextUtils.isEmpty(username)){
  53.  
  54. listener.onUsernameError(); //Callback listener in the model layer
  55.  
  56. error = true ;
  57.  
  58. }
  59.  
  60. if (TextUtils.isEmpty( password )){
  61.  
  62. listener.onPasswordError();
  63.  
  64. error = true ;
  65.  
  66. }
  67.  
  68. if (!error){
  69.  
  70. listener.onSuccess();
  71.  
  72. }
  73.  
  74. }
  75.  
  76. }, 2000);
  77.  
  78. }
  79.  
  80. }

2.2 View layer description and specific code

Responsible for displaying data, providing a friendly interface for user interaction. Activity, Fragment and View subclasses under MVP are reflected in this layer. Activity generally loads UI views, sets listeners and then hands them over to Presenter for processing, so it also needs to hold a reference to the corresponding Presenter. What this layer needs to do is to call the relevant methods of the presenter every time there is a corresponding interaction. (For example, button click)

  1. package com.nsu.edu.androidmvpdemo.login;
  2.  
  3.   
  4.  
  5. /**
  6.  
  7. * Created by Anthony on 2016/2/15.
  8.  
  9. * Class Note: The interface of the login View , the implementation class is the login activity
  10.  
  11. */
  12.  
  13. public interface LoginView {
  14.  
  15. void showProgress();
  16.  
  17.   
  18.  
  19. void hideProgress();
  20.  
  21.   
  22.  
  23. void setUsernameError();
  24.  
  25.   
  26.  
  27. void setPasswordError();
  28.  
  29.   
  30.  
  31. void navigateToHome();
  32.  
  33. }
  34.  
  35.  
  36. package com.nsu.edu.androidmvpdemo.login;
  37.  
  38.   
  39.  
  40. import android.app.Activity;
  41.  
  42. import android.content.Intent;
  43.  
  44. import android.os.Bundle;
  45.  
  46. import android. view . View ;
  47.  
  48. import android.widget.EditText;
  49.  
  50. import android.widget.ProgressBar;
  51.  
  52. import android.widget.Toast;
  53.  
  54.   
  55.  
  56. import com.nsu.edu.androidmvpdemo.R;
  57.  
  58.   
  59.  
  60. /**
  61.  
  62. * Created by Anthony on 2016/2/15.
  63.  
  64. * Class Note: In the MVP mode, the View layer corresponds to an activity, which is the login activity.
  65.  
  66. */
  67.  
  68. public class LoginActivity extends Activity implements LoginView, View .OnClickListener {
  69.  
  70.   
  71.  
  72. private ProgressBar progressBar;
  73.  
  74. private EditText username;
  75.  
  76. private EditText password ;
  77.  
  78. private LoginPresenter presenter;
  79.  
  80.   
  81.  
  82. @Override
  83.  
  84. protected void onCreate(Bundle savedInstanceState) {
  85.  
  86. super.onCreate(savedInstanceState);
  87.  
  88. setContentView(R.layout.activity_login);
  89.  
  90.   
  91.  
  92. progressBar = (ProgressBar) findViewById(R.id.progress);
  93.  
  94. username = (EditText) findViewById(R.id.username);
  95.  
  96. password = (EditText) findViewById(R.id. password );
  97.  
  98. findViewById(R.id.button).setOnClickListener(this);
  99.  
  100.   
  101.  
  102. presenter = new LoginPresenterImpl(this);
  103.  
  104. }
  105.  
  106.   
  107.  
  108. @Override
  109.  
  110. protected void onDestroy() {
  111.  
  112. presenter.onDestroy();
  113.  
  114. super.onDestroy();
  115.  
  116. }
  117.  
  118.   
  119.  
  120. @Override
  121.  
  122. public void showProgress() {
  123.  
  124. progressBar.setVisibility( View .VISIBLE);
  125.  
  126. }
  127.  
  128.   
  129.  
  130. @Override
  131.  
  132. public void hideProgress() {
  133.  
  134. progressBar.setVisibility( View .GONE);
  135.  
  136. }
  137.  
  138.   
  139.  
  140. @Override
  141.  
  142. public void setUsernameError() {
  143.  
  144. username.setError(getString(R.string.username_error));
  145.  
  146. }
  147.  
  148.   
  149.  
  150. @Override
  151.  
  152. public void setPasswordError() {
  153.  
  154. password .setError(getString(R.string.password_error));
  155.  
  156. }
  157.  
  158.   
  159.  
  160. @Override
  161.  
  162. public void navigateToHome() {
  163.  
  164. // TODO startActivity(new Intent(this, MainActivity.class));
  165.  
  166. Toast.makeText(this, "login success" ,Toast.LENGTH_SHORT).show();
  167.  
  168. // finish();
  169.  
  170. }
  171.  
  172.   
  173.  
  174. @Override
  175.  
  176. public void onClick( View v) {
  177.  
  178. presenter.validateCredentials(username.getText().toString(), password .getText().toString());
  179.  
  180. }
  181.  
  182.   
  183.  
  184. }

2.3 Presenter layer description and specific code

Presenter plays the role of the middle layer between view and model. It builds the view layer after obtaining the data of the model layer; it can also distribute the processing logic after receiving the feedback command on the view layer UI and hand it over to the model layer for business operations. It can also determine various operations of the view layer.

  1. package com.nsu.edu.androidmvpdemo.login;
  2.  
  3.   
  4.  
  5. /**
  6.  
  7. * Created by Anthony on 2016/2/15.
  8.  
  9. * Class Note: The interface of the login Presenter, the implementation class is LoginPresenterImpl, which completes the login verification and destroys the current view  
  10.  
  11. */
  12.  
  13. public interface LoginPresenter {
  14.  
  15. void validateCredentials(String username, String password );
  16.  
  17.   
  18.  
  19. void onDestroy();
  20.  
  21. }
  22.  
  23.  
  24. package com.nsu.edu.androidmvpdemo.login;
  25.  
  26.   
  27.  
  28. /**
  29.  
  30. * Created by Anthony on 2016/2/15.
  31.  
  32. * Class Note:
  33.  
  34. * 1 Complete the implementation of presenter. This mainly involves the interaction and operation between the Model layer and the View layer.
  35.  
  36. * 2 There is also an OnLoginFinishedListener in presenter,
  37.  
  38. * It is implemented in the Presenter layer, calls back to the Model layer, and changes the state of the View layer.
  39.  
  40. * Ensure that the Model layer does not directly operate the View layer. If this interface is not implemented in LoginPresenterImpl,
  41.  
  42. * LoginPresenterImpl only has references to View and Model, so how does Model tell View the result ?
  43.  
  44. */
  45.  
  46. public class LoginPresenterImpl implements LoginPresenter, OnLoginFinishedListener {
  47.  
  48. private LoginView loginView;
  49.  
  50. private LoginModel loginModel;
  51.  
  52.   
  53.  
  54. public LoginPresenterImpl(LoginView loginView) {
  55.  
  56. this.loginView = loginView;
  57.  
  58. this.loginModel = new LoginModelImpl();
  59.  
  60. }
  61.  
  62.   
  63.  
  64. @Override
  65.  
  66. public void validateCredentials(String username, String password ) {
  67.  
  68. if (loginView != null ) {
  69.  
  70. loginView.showProgress();
  71.  
  72. }
  73.  
  74.   
  75.  
  76. loginModel.login(username, password , this);
  77.  
  78. }
  79.  
  80.   
  81.  
  82. @Override
  83.  
  84. public void onDestroy() {
  85.  
  86. loginView = null ;
  87.  
  88. }
  89.  
  90.   
  91.  
  92. @Override
  93.  
  94. public void onUsernameError() {
  95.  
  96. if (loginView != null ) {
  97.  
  98. loginView.setUsernameError();
  99.  
  100. loginView.hideProgress();
  101.  
  102. }
  103.  
  104. }
  105.  
  106.   
  107.  
  108. @Override
  109.  
  110. public void onPasswordError() {
  111.  
  112. if (loginView != null ) {
  113.  
  114. loginView.setPasswordError();
  115.  
  116. loginView.hideProgress();
  117.  
  118. }
  119.  
  120. }
  121.  
  122.   
  123.  
  124. @Override
  125.  
  126. public void onSuccess() {
  127.  
  128. if (loginView != null ) {
  129.  
  130. loginView.navigateToHome();
  131.  
  132. }
  133.  
  134. }
  135.  
  136. }

2.4 Login callback interface

  1. package com.nsu.edu.androidmvpdemo.login;
  2.  
  3.   
  4.  
  5. /**
  6.  
  7. * Created by Anthony on 2016/2/15.
  8.  
  9. * Class Note: Login event monitoring
  10.  
  11. */
  12.  
  13. public interface OnLoginFinishedListener {
  14.  
  15.   
  16.  
  17. void onUsernameError();
  18.  
  19.   
  20.  
  21. void onPasswordError();
  22.  
  23.   
  24.  
  25. void onSuccess();
  26.  
  27. }

The code flow of the demo is as follows: (Please refer to the class diagram below)

1 Activity does some UI initialization and needs to instantiate the corresponding LoginPresenter reference and implement the LoginView interface to monitor interface actions

2 After the login button is pressed, the login event is received. In onClick, it is passed to LoginPresenter for processing through the reference of LoginPresenter. LoginPresenter receives the login logic and knows that it is time to log in.

3 Then LoginPresenter displays the progress bar and passes the logic to our Model, which is the LoginModel here (LoginModelImpl, the implementation class of LoginModel), and at the same time passes OnLoginFinishedListener, which is LoginPresenter itself, to our Model (LoginModel).

4 After LoginModel finishes processing the logic, the result is notified to LoginPresenter through OnLoginFinishedListener callback

5 LoginPresenter returns the result to the view layer's Activity, and the activity displays the result

Please refer to this class diagram:

Class diagram of this project

(3) Note:

3.1 There is also an OnLoginFinishedListener in the presenter, which is implemented in the Presenter layer. It calls back the Model layer and changes the state of the View layer to ensure that the Model layer does not directly operate the View layer.

3.2 In a good architecture, the model layer may only be an entrance to the domain layer and the business logic layer. If we refer to the popular Uncle Bob clean architecture on the Internet, the model layer may be an interactor that implements business use cases. This aspect should be covered in subsequent articles, but the current capabilities are limited.

(4)MVP Classic Reference Materials

Please refer to the article directly, there are a lot of learning materials about the MVP mode:

  • Android architecture collection (please follow github, it will be updated later)
  • android mvp github address (This blog is based on this project. This project is also very simple, divided into two modules, login and main, a total of ten classes, the idea is very clear. Friends who are learning can directly clone and view the source code.)

The src code of androidmvp is divided into two modules: login and main

For simple operation, this project only adds the login module

The github address of this project:

https://github.com/CameloeAnthony/AndroidMVPDemo

<<:  Summary of Common Methods for Custom Controls

>>:  Android immersive status bar implementation

Recommend

Model Y's rival? The B-class pioneer hunting SUV Song L is here!

On August 25, the B-class pioneer hunting SUV BYD...

The growth formula of Liu Genghong's live broadcast room

Recently, Liu Genghong’s live broadcast has becom...

How to create opium-like articles that users can’t stop reading? (Down)

Fear, excitement, novelty and confusion - what ki...

Kuaishou Operation丨The delivery and process of Kuaishou advertising

According to the "2019 Internet Service Indu...

10 predictions for video games in 2016

2015 is aptly called the first year of Chinese TV...

A number about Harvard graduates

In 2007, 44% of Harvard graduates entered the fin...

What is the main function of Apple Pay?

After nearly two years of release and various twi...