Skip to content

Android Architecture: MVC vs MVP vs MVVM

Architecture has been no small topic in Android. By simply managing where our logic and data is contained, our app suddenly becomes more functional and testable. We become able to leverage the full extent of libraries like RxJava and LiveData.

Most of us must have heard of the big 3 architecures: MVC, MVP, and MVVM. Each of these separate your app into 3 major components, each with its own set of responsibilities.

Their differences, while subtle, makes huge differences in the way the app functions. Each blogger has their own opinions of each one of them but here, we’re going to go over each one of them and decide for once and for all which one truly comes out on top.

MVC (Model-View-Controller)

Ahh the ancient one, it is that which started it all. Let’s look at its 3 components.

Model

This is the data layer. Everything directly data-related goes in the Model. Business logic is handled here as well as network APIs and database fetches. The Model is coded in the form of POJOs.

public class User {

    private String email;

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
    
}

View

This is the UI layer, a visual representation of the Model. The View is concerned with rendering the display to the user but tends to not know the underlying state of the app or what happens with any user interactions. The View is coded in the form of XML files and layouts.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/et_email"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

Controller

This is the logic layer and what brings the Model and View together. The Controller decides what to do when any buttons are clicked and upon any changes to the data contained in the Model, the Controller can decide to update the state of the View. The Controller is coded in the form of Activities.

public class LoginActivity extends Activity implements LoginListener {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.login_layout);
	}
	
	
	@Override
	public void onLoginSuccess() {
		Intent intent = new Intent(this, WelcomeActivity.class);
		this.startActivity(intent);
	}
}

Advantages and Disadvantages

+ Model and View are well separated and thus, easy to test

+ XML code tends to remain simple

– Controller is tied too closely to Android APIs and thus, difficult to test

– Changing the View demands corresponding changes to the Controller

– Controller can easily get too bloated with code and thus could become difficult to maintain

MVP (Model-View-Presenter)

MVP fixes the underlying problems of MVC by separating the View and the Controller (which is now called the Presenter).

Model

Exactly the same as MVC

View

The View now includes Activities and Fragments and thus, properly contains the full front-end. A View Interface is used so that the Presenter has an interface to interact with and has the added bonus of eliminating any coupling to specific views and thus, lets us perform tests with mock representations of views.

public class LoginActivity extends AppCompatActivity implements LoginView {
    
    private EditText username;
    private EditText password;
    private LoginPresenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        progressBar = findViewById(R.id.progress);
        username = findViewById(R.id.username);
        password = findViewById(R.id.password);
        findViewById(R.id.button).setOnClickListener(v -> validateCredentials());

        presenter = new LoginPresenter(this, new LoginInteractor());
    }

    @Override
    public void navigateToHome() {
        startActivity(new Intent(this, MainActivity.class));
        finish();
    }

    private void validateCredentials() {
        presenter.validateCredentials(username.getText().toString(), password.getText().toString());
    }
    
}
public interface LoginView {
    void navigateToHome();  
}

Presenter

Instead of being an activity, the Presenter is now its own class. It interacts with the View through the previously mentioned interface. Apart from that, its job is pretty much the same as the controller’s. You’re essentially just responding to data being fetched in the Model as well as user interactions.

MVP purists tend to think the Presenter should make zero use of Android APIs for the sake of making it even easier to test with. This of course, isn’t a strict rule and goes down completely to the style of the developer.

public class LoginPresenter {

    private LoginView loginView;

    LoginPresenter(LoginView loginView) {
        this.loginView = loginView;
    }

    public void validateCredentials(String username, String password) {
        handleLogin(username, password);
    }
    
}

Advantages and Disadvantages

+ Each component can now be individually edited and tested as none of them are tied too closely to one another

+ XML code tends to remain simple

– Maintenance is still a problem as Presenter code can still get easily bloated with business logic

MVVM (Model-View-View Model)

The MVVM architecture makes full use of data binding trends that have been taking over the ecosystem these past few years. Doing so reduces the bloat previously contained in the Controller/Presenter with the added bonus of making the new “View Model” more modular and easier to test.

MVVM makes use of data binding libraries such as LiveData or RxJava.

Model

Same as MVC and MVP

View

In addition to how it was in MVP, View classes subscribe to Observable streams prepared in the View Model.

class LoginActivity : AppCompatActivity() {

    private lateinit var viewModel : LoginViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)

        viewModel = ViewModelProviders.of(
            this,
            LoginViewModelFactory(LoginInteractor())
        )[LoginViewModel::class.java]

        viewModel.loginState.observe(::getLifecycle, ::updateUI)

        button.setOnClickListener { onLoginClicked() }
    }

    private fun onLoginClicked() {
        viewModel.onLoginClicked(username.text.toString(), password.text.toString())
    }

}

View Model

Just like the Presenter, the View Model contains business logic and isn’t tied directly to the view. The View Model however, replaces much of the traditional business logic for preparation of Observable streams, ready for the View to subscribe to them.

class LoginViewModel(private val loginInteractor: LoginInteractor) : ViewModel(),
    LoginInteractor.OnLoginFinishedListener {

    private val _loginState: MutableLiveData<ScreenState<LoginState>> = MutableLiveData()

    val loginState: LiveData<ScreenState<LoginState>>
        get() = _loginState

    fun onLoginClicked(username: String, password: String) {
        _loginState.value = ScreenState.Loading
        loginInteractor.login(username, password, this)
    }
}

Advantages and Disadvantages

+ Testing is even easier as there’s no more need to mock Views when testing the View Model (as previously needed with the Presenter)

+ Even less dependent on Android APIs

+ Great event-based architecture makes single screen apps easier to write

– XML code becomes increasingly complex

– Becomes a chore for apps with more than a single screen/activity

– High number of observable streams can make the app hard to maintain if not done carefully

Which is the best?

I think most people can agree that MVC has lived its life but now, the war is between MVP and MVVM. Both do a good job of keeping the app modular, easy to test, and are simpler and more complex in different areas.

I personally think there are situations where each one shines. Keep in mind that MVVM is the more event-driven structure. This makes it more effective in responding to heavy loads of:

  • Database and API fetch operations
  • Clicks, Gestures, and other user interactions
  • System updates (Bluetooth, GPS, Gyroscope, etc.)

MVVM however does become harder to maintain with an increasing number of activities as the subscribing and unsubscribing to observable streams has to be managed per activity.

My verdict is to weigh the number of desired activities to the intensity of events contained in each one of them. MVP deals better with more activities but MVVM deals better with high loads of events in each one of them.