MVC (Model View Controller)
This is one of the most widely used approaches in software development. The MVC consists of three main components:
All of these components interact with each other and perform specific tasks, as shown in the following figure.
The key points of MVC is:
It has been noticed that Android is not able to follow the MVC architecture completely, as activity/fragment can act as both the controller and the view, which makes all the code cluttered in one place. Activity/fragment can be used to drawmultiple views for a single screen in an app, thus all different data calls and views are populated in the same place. Therefore, to solve this problem, we can use different design patterns or can implement MVC carefully by taking care of conventions and following proper programming guidelines.
The following shows a basic example of how MVC is used in Android.
Model.
public class LocationItem { String name; String address; public LocationItem(String name, String address) { this.name = name; this.address = address; } public String getName() { return name; } public String getAddress() { return address; } }
View.
<TextView android:id="@+id/tvName" android:layout_width="wrap_content" android:layout_height="wrap_content" />
Controller.
LocationItem item = new LocationItem("Name", "Address"); TextView tvName = (TextView) findViewById(R.id.tvName); tvName.setText(item.getName());
The model here is LocationItem
, which holds the name and address of the location. The view is an XML file, which contains a TextView
, through which the name of the location can be displayed. The activity, which is the controller, contains a LocationItem
. It gets the name of the LocationItem
sets it up in the view, which displays it.
MVP (Model View Presenter)
Model View Presenter (MVP) is derived from the MVC pattern. MVP is used to minimize the high dependency on the view, which is the case in the MVC. It separates the view and model by using the presenter. The presenter decides what should be displayed on the view.
The interaction between the various components of the MVP are shown in the following figure.
In the MVP design, the presenter communicates with the view through interfaces. The interfaces are defined in the presenter class, to which it passes the required data. The activity/fragment or any other view component implements the interfaces and renders the data in a way they want. The connection between the presenter and the view is one to one.
Important points of MVP are:
List of functionalities of the Presenter are
Following are some reasons which makes MVP a good architectural pattern for Android:
View
, it is more easier to perform unit testing while developing your application.In this example, we will show how the MVP design can be used to display a list into a RecyclerView.
public interface LocationInteractor { interface OnLoadFinishedListener { void onSuccess(List<LocationItem> items); void onFailed(); } void loadLocations(OnLoadFinishedListener listener); }
Here we have a LocationInteractor
class that is used by the presenter to communicate with the model
public class LocationInteractorImpl implements LocationInteractor { @Override public void loadLocations(final OnLoadFinishedListener listener) { RetroInterface.getRssFeedApi().getFeed("", new Callback<LocationResponse>() { @Override public void success(LocationResponse locationResponse, Response response) { if (listener != null) { if (locationResponse != null) { listener.onSuccess(locationResponse.getDetails()); } else { listener.onFailed(); } } } @Override public void failure(RetrofitError error) { if (listener != null) { listener.onFailed(); } } }); } }
This is the LocationInteractorImpl
class which is the model. This class interacts with the presenter to provide the list of locations. The loadLocations
function is used by the presenter to interact with the model and fetchthe list of locations.
The model (LocationInteractorImpl
) then uses the listener.onSuccess
and listener.onFailed
methods to send results back to the presenter:
public interface LocationInterface { void showProgress(); void hideProgress(); void locationLoaded(List<LocationItem> items); }
The LocationInterface
class is used by the presenter to communicate with the view:
public interface LocationPresenter { void loadLocations(); void onDestroy(); }
The LocationPresenter
class is used by the view to communicate with the presenter. Depending on the functions called by the view, the presenter will communicate with the model and get the responses:
public class LocationPresenterImpl implements LocationPresenter, LocationInteractor.OnLoadFinishedListener { private LocationInterface locationInterface; private LocationInteractor locationInteractor; public LocationPresenterImpl(LocationInterface locationInterface) { this.locationInterface = locationInterface; this.locationInteractor = new LocationInteractorImpl(); } @Override public void loadLocations() { if (locationInterface != null) { locationInterface.showProgress(); } locationInteractor.loadLocations(this); } @Override public void onDestroy() { locationInterface = null; } @Override public void onSuccess(List<LocationItem> items) { if (locationInterface != null) { locationInterface.locationLoaded(items); locationInterface.hideProgress(); } } @Override public void onFailed() { if (locationInterface != null) { locationInterface.locationLoaded(null); locationInterface.hideProgress(); } } }
The LocationPresenterImpl
class is the presenter class which communicates between the view and the model. This class implements LocationPresenter
with which the view communicates with the presenter and the LocationInteractor.OnLoadFinishedListener
from which the model communicates with the presenter.
When the view calls the loadLocations
function of the presenter, the presenter interacts with the model and calls the loadLocations
method of the model, indicating that the model is to return the list of locations to be displayed.
The onSuccess
and onFailed
functions are then called by the model after the list has been fetched successfully or has failed. Then the presenter communicates with the view through the locationLoaded
function. Here, it passes the list that has been fetched by the model.
public class LocationListActivity extends Activity implements LocationInterface { private ProgressBar progressBar; RecyclerView recyclerView; List<LocationItem> items; AddPlacesAdapter adapter; private LocationPresenter presenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); progressBar = (ProgressBar) findViewById(R.id.progress); recyclerView = (RecyclerView) findViewById(R.id.recyclerView); items = new ArrayList<>(); adapter = new AddPlacesAdapter(this, items); adapter.setClickListener(new AddPlacesAdapter.ClickListener() { @Override public void onItemClickListener(View v, int pos) { // handle click events } }); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(adapter); presenter = new LocationPresenterImpl(this); presenter.loadLocations(); } @Override protected void onDestroy() { presenter.onDestroy(); super.onDestroy(); } @Override public void showProgress() { progressBar.setVisibility(View.VISIBLE); } @Override public void hideProgress() { progressBar.setVisibility(View.GONE); } @Override public void locationLoaded(List<LocationItem> items) { if(items!=null) { this.items = items; adapter.refresh(items); } } }
The LocationListActivity
is the view where all the interaction with the user will happen. The view implements the LocationInterface
, by which it gets the responses from the presenter. The view uses an instance of the presenter.
presenter = new LocationPresenterImpl(this);
It then calls the presenter.loadLocations()
to tell the presenter that it wants the list of locations to be displayed.
So, the key points of MVP is:
The supposed benefit of MVP is that there is a well-defined contract between Presenter and View, and it can be verified that "under the right circumstances, the Presenter calls the right methods on the View".
There is hidden cost that the Presenter is typically bound to a single View, so argument passing between Presenters and hierarchic relations of the Views themselves can introduce difficulty: maintaining the existence of and communication between child presenters and sibling presenters (if they exist) is tricky. This can be avoided if the Presenter is shared between Views of the same flow.
The downside is that:
MVVM
MVVM stands for Model-View-View-Model. It is similar to the MVC model, the only difference being it has two-way data binding with the view and view-model. The changes in the view are being propagated via the view-model, which uses an observer pattern to communicate between the view-model and the model. The view in this case is completely isolated from the model.
The major advantage of using MVVM is it enables automatic changes in the view via the view-model:
MVVM has the following components:
Many views can be linked to one view-model, which creates a many-to-one relationbetween the view and a view-model. Also, a view has information about the view-model but the view-model does not have any information about the view. The view is not responsible for the state of information; rather, that is being managed by the view-model and the view and the model are only reflected via the changes made to the view-model.
In developer's terminology, one can say that the view-model is the interface between a designer and a coder.
The key points of MVVM is: