time

Understanding MVC, MVP, MVVM patterns in Android

MVC (Model View Controller)

This is one of the most widely used approaches in software development. The MVC consists of three main components:

  • Model. The model represents the object in the application. This has the logic of where the data is to be fetched from. This can also have the logic by which the controller can update the view. In Android, the model is mostly represented by object classes.
  • View. The view consists of the components that can interact with the user and is responsible for how the model is displayed in the application. In Android, the view is mostly represented by the XML where the layouts can be designed.
  • Controller. The controller acts as a mediator between the model and the view. It controls the data flow into the model object and updates the view whenever data changes. In Android, the controller is mostly represented by the activities and fragments.

All of these components interact with each other and perform specific tasks, as shown in the following figure.

android_mvc.png

The key points of MVC is:

  • The user’s interactions call methods on the Controller
  • The Controller updates the Model (where the model is what actually stores state)
  • The Model exposes change listeners to notify observers that it has changed
  • The View subscribes for changes emitted by the model to update itself

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.

  • Model. The model represents the objects in the application. This has the logic of where the data is to be fetched from.
  • View. The view renders information to users and contains a UI Component .xml file, activity, fragments, and dialog under the View Layer. It does not have any other logic implemented.
  • Presenter. The presenter layer performs the task of the controller and acts as the mediator between the view and model. But unlike the controller, it is not dependent on the view. The view interacts with the presenter for the data to be displayed, and the presenter then takes the data from the model and returns it to the view in a presentable format. The presenter does not contain any UI components; it just manipulates data from the model and displays it on the view.

The interaction between the various components of the MVP are shown in the following figure.

android_mvp.png

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:

  • A View’s sole responsibility is to draw UI as instructed by the Presenter. It is a dumb part of the application.
  • View delegates all the user interactions to its Presenter.
  • The View never communicates with Model directly.
  • The Presenter is responsible for delegating View’s requirements to Model and instructing View with actions for specific events.
  • Model is responsible for fetching the data from server, database and file system.
android_mvp2.png

List of functionalities of the Presenter are

  • Interacting with OS
  • Handling User Input/Requests and producing the result
  • Hhandling communication between the View and the Model
  • Maintaining the state of the application
  • Encapsulate all of the applications business logic

Following are some reasons which makes MVP a good architectural pattern for Android:

  1. Makes debugging easier in Applications .  MVP enforces three different layers of abstractions which makes it easier to debug your applications. Moreover, since business logic is completely decoupled from View, it is more easier to perform unit testing while developing your application.
  2. Enforces better separation of Concerns.  MVP does the great job of separating out your business logic and persistence logic out of your Activity and Fragment classes which in turn better enforce good separation of concerns.
  3. Code Re-usability.  In MVP, the code can be better reused since you can have multiple presenters controlling your Views. This is more important as you definitely don’t want to rely on a single presenter to control your different Views.

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 user’s interactions call methods on the Presenter
  • The Presenter stores state, manages state, and calls methods on the view to notify it to update itself
  • The Model is just data
  • The View receives method calls from the presenter to be notified of changes to update itself

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:

  • the Presenter stores the state, so we must be able to persist/restore the presenter state when the process is re-created
  • the View is updated via callbacks, which is more manual work than listening for changes
  • if the Presenter can survive configuration changes, then it is possible for the View to be detached when Presenter receives asynchronous results, and there is a chance that method calls to the View can be dropped

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:

android_mvvm.png

MVVM has the following components:

  • Model. The model represents the objects in the application. This has the logic of where the data is to be fetched from.
  • View. The view is similar to the MVC pattern view, which renders information to users and contains a UI Component .xml file, activity, fragments, and dialog under the View Layer. It does not have any other logic implemented.
  • View-model. The view-model helps in maintaining the state of the view and does changes to the model based on the inputs gained from the view.

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:

  • The user’s interactions call methods on the ViewModel
  • The ViewModel stores state, manages state, and exposes change events when the state changes
  • The Model is the data mapped into the observable fields (or any other form of event emission)
  • The View subscribes for change events exposed by the viewmodel to update itself