By Jeff Angelini posted on 7/20/2011 2:35:00 PM
Separating the presentation of the application ' s UI from the logic's UI is usually a good idea. This separation of concerns creates more de-coupled code, which are much cleaner, and even allows for more unit testing CoV Erage. Android bundles the UI and UI logic into the activity class, which necessitates instrumentation to test the activity. Since instrumentation is introduced, it's much more difficult (or impossible) to properly unit test your UI logic when th e dependencies in the code cannot is mocked. However, a simple MVP pattern would help de-couple the UI and UI logic in Android applications.
The MVP pattern stands for model-view-presenter, and it separates the UI concerns between the data of the UI (Model), the Display of the UI (View), and the logic of the UI (Presenter). For Android, the View is the Activity, which would handle gathering user input and updating the display; The Presenter is a class that would handle communication between the Model and View; The Model would handle persisting and retrieving data, along with any business logic, the data must adhere to. Interfaces'll is used to de-couple for each of the these components. A simple Customer View is used to illustrate how this can is accomplished.
First, our customeractivity (the View) would have textboxes for the Customer's ID, first name, and last name:
private EditText mFirstNameEditText, mLastNameEditText, mIdEditText;
The user would load a customer using the Midedittext and a load Button. Likewise, the user would save a customer using a save Button:
private Button mSaveButton, LoadButton;
We must now create a customerpresenter with the following methods:
public CustomerPresenter(ICustomerView View)public void saveCustomer (String firstName, String lastName) public void loadCustomer (int id)
We then can wire it all up in the Customeractivity ' s OnCreate method:
mCustomerPresenter = new CustomerPresenter(this); mSaveButton.setOnClickListener(this); mLoadButton.setOnClickListener(this);
The Customeractivity class must now implement the interfaces Onclicklistener (for handling the Button ' s onclicklisteners) and Icustomerview (for the Customerpresenter constructor). The Onclicklistener defines the method void OnClick (View v), and our method would look like the following:
switch (v.getId()) {case R.id.saveButton: mCustomerPresenter.saveCustomer(mFirstNameEditText.getText().toString(),mLastNameEditText.getText().toString());break;case R.id.loadButton: mCustomerPresenter.loadCustomer(Integer.parseInt(mIdEditText.getText().toString()));break;
The previous, sections show, the Save Button is clicked, and the Savecustomer method of our presenter would be Called with the Customer's first name and last name information; And when the Load Button was clicked, the Loadcustomer method of our presenter would be called.
We haven ' t defined Icustomerview, so we'll do it now. When loading the customer, the customerpresenter would need to being able to update the customeractivity's last name, first NA Me, and ID edittexts, so Icustomerview would look like the following:
void setLastName (String lastName); void setFirstName (String firstName);void setId(int id);
The customeractivity ' s implementation of these methods would set the corresponding EditText to the value of the parameter.
The Customerpresenter, then, would look like the following:
private ICustomerView mCustomerView;private ICustomerModel mCustomerModel;public CustomerPresenter(ICustomerView view) {mCustomerView = view;mCustomerMode = new CustomerModel();}@Overridepublic void saveCustomer(String firstName, String lastName) {mCustomerModel.setFirstName(firstName);mCustomerModel.setLastName(lastName);}@Overridepublic void loadCustomer(int id) {(mCustomerModel.load(id)) {mCustomerView.setId(mCustomerModel.getId());mCustomerView.setFirstName(mCustomerModel.getFirstName());mCustomerView.setLastName(mCustomerModel.getLastName());}}
The implementation of the Customermodel isn ' t important for our purposes; We just need to know that it's being saved to a repository of some sort. Furthermore, the Customermodel is currently tightly-coupled to the Customerpresenter, which can remedied by injecting I T as a dependency.
The Customerpresenter allows the Customeractivity class to is as simple as possible. The activity now is gathers user input for the presenter and provides simple UI update methods for the presenter. Since the Customerview and Customermodel implement interfaces and can be injected into the customerpresenter, it's not de Pendent on them. Therefore, they can by mocked, which allows the Customerpresenter logic to be unit tested.
After Note:this MVP pattern was sometimes referred to as Passive view, since the view only passes along data, either to or From its presenter. The MVP pattern can also is implemented such that the View knows of the model. The view responds to state changes in the model for simple UI updates, while the presenter handles more complex UI logic. This and complex pattern is a sometimes referred to as supervising Controller.
In Android, this can is accomplished by the Model using Java ' s Observable class and the View implementing the Observer int Erface; When something changes in the Model, it can call the Observable ' s Notifyobservers method. It can also is implemented with Android ' s Handler class; When something changes in the Model, it can send a message to a handler that the View injects into it.
Use MVP mode to decouple and increase testability in andoid development