Why use the MVP pattern?
One of the problems with traditional Android development is the tight coupling between Activities and business logic. This tends to make testing, extensibility and maintenance rather difficult.
The main idea behind using MVP is to take abstract away most (or all) of the business logic into separate entities (presenters) and only keep the UI logic in Activities.
There are many different types of MVP implementations for Android out there, this article only focuses on the basic principles behind them.
Presenter:
The presenter is a separate class that contains the business logic and a reference to its associated view.
The view itself is abstracted away through an interface. This is implemented mainly to allow the view to be mocked in a unit test or replaced with any other view that implements this particular interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class Presenter { //The associated view MainView mainView; public Presenter(MainView mainView) { this.mainView = mainView; } /** * Some business logic */ public void getSomeResult() { //call a method from the view mainView.showToast("Here's your result!"); } } |
View:
The view is defined as an Interface which can be implemented by any Activity, Fragment or any type of Android View. This view contains methods that handle all UI logic.
1 2 3 4 5 6 7 8 |
public interface MainView { void showLoading(boolean loading); void displayResult(String result); void showToast(String message); } |
Finally
The last step is to link everything together: a new Activity is created which holds a reference to the presenter and implements the View Interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
public class MainActivity extends Activity implements MainView { private TextView textView; private ProgressDialog progress; private Presenter presenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Initialize the presenter. presenter = new Presenter(this); textView = (TextView) findViewById(R.id.textView); progress = new ProgressDialog(this); progress.setTitle("Loading"); progress.setMessage("Wait while loading..."); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //execute some business logic presenter.startSomeTask(); } }); findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //execute some additional business logic presenter.getSomeResult(); } }); } @Override public void showLoading(boolean loading) { if (loading) { progress.show(); } else { progress.dismiss(); } } @Override public void displayResult(String result) { textView.setText(result); } @Override public void showToast(String message) { Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show(); } } |
Get the full sample project here.