Swiftorial Logo
Home
Swift Lessons
Matchups
CodeSnaps
Tutorials
Career
Resources

MVP Pattern in Android Development

Introduction

The MVP (Model-View-Presenter) pattern is a derivative of the MVC (Model-View-Controller) pattern commonly used in software engineering. In Android development, the MVP pattern helps to separate the concerns of the application, making the code more modular, easier to understand, and more maintainable.

Components of MVP

The MVP pattern consists of three main components:

  • Model: This layer is responsible for handling the data part of the application. It can be data from a database, web service, or any other data source.
  • View: This layer is responsible for displaying the data and UI elements to the user. It receives user interactions and passes them to the Presenter.
  • Presenter: This layer acts as a middleman between the Model and the View. It retrieves data from the Model and applies the logic needed to update the View.

Setting Up MVP in an Android Project

Let's create a simple Android application that demonstrates the MVP pattern. This example will involve a basic login screen. Follow the steps below to set up the project:

Step 1: Create the Interfaces

First, we'll create interfaces for the View and the Presenter. These interfaces will define the contract between the View and the Presenter.

public interface LoginView {
    void showProgress();
    void hideProgress();
    void setUsernameError();
    void setPasswordError();
    void navigateToHome();
}
public interface LoginPresenter {
    void validateCredentials(String username, String password);
    void onDestroy();
}

Step 2: Implement the View Interface

Next, we'll create an activity that implements the LoginView interface. This activity will be responsible for updating the UI based on the actions performed by the user.

public class LoginActivity extends AppCompatActivity implements LoginView {
    
    private EditText username;
    private EditText password;
    private Button loginButton;
    private ProgressBar progressBar;
    private LoginPresenter presenter;

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

        username = findViewById(R.id.username);
        password = findViewById(R.id.password);
        loginButton = findViewById(R.id.login_button);
        progressBar = findViewById(R.id.progress_bar);

        presenter = new LoginPresenterImpl(this);

        loginButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.validateCredentials(username.getText().toString(), password.getText().toString());
            }
        });
    }

    @Override
    public void showProgress() {
        progressBar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideProgress() {
        progressBar.setVisibility(View.GONE);
    }

    @Override
    public void setUsernameError() {
        username.setError("Username is required");
    }

    @Override
    public void setPasswordError() {
        password.setError("Password is required");
    }

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

Step 3: Implement the Presenter Interface

Now, we'll create a class that implements the LoginPresenter interface. This class will handle the business logic and communicate with the Model to retrieve data.

public class LoginPresenterImpl implements LoginPresenter {
    
    private LoginView loginView;
    private LoginInteractor loginInteractor;

    public LoginPresenterImpl(LoginView loginView) {
        this.loginView = loginView;
        this.loginInteractor = new LoginInteractorImpl();
    }

    @Override
    public void validateCredentials(String username, String password) {
        if (loginView != null) {
            loginView.showProgress();
        }
        loginInteractor.login(username, password, new LoginInteractor.OnLoginFinishedListener() {
            @Override
            public void onUsernameError() {
                if (loginView != null) {
                    loginView.setUsernameError();
                    loginView.hideProgress();
                }
            }

            @Override
            public void onPasswordError() {
                if (loginView != null) {
                    loginView.setPasswordError();
                    loginView.hideProgress();
                }
            }

            @Override
            public void onSuccess() {
                if (loginView != null) {
                    loginView.navigateToHome();
                }
            }
        });
    }

    @Override
    public void onDestroy() {
        loginView = null;
    }
}

Step 4: Implement the Model

Finally, we'll implement the Model, which will handle the login logic. In this example, we'll just check if the username and password are not empty.

public interface LoginInteractor {
    interface OnLoginFinishedListener {
        void onUsernameError();
        void onPasswordError();
        void onSuccess();
    }

    void login(String username, String password, OnLoginFinishedListener listener);
}
public class LoginInteractorImpl implements LoginInteractor {
    
    @Override
    public void login(final String username, final String password, final OnLoginFinishedListener listener) {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                if (TextUtils.isEmpty(username)) {
                    listener.onUsernameError();
                    return;
                }
                if (TextUtils.isEmpty(password)) {
                    listener.onPasswordError();
                    return;
                }
                listener.onSuccess();
            }
        }, 2000);
    }
}

Conclusion

By following the MVP pattern, you can achieve a clean separation of concerns in your Android applications. This separation makes your code more modular, testable, and maintainable. In this tutorial, we created a simple login screen to demonstrate how to implement the MVP pattern in an Android project. You can expand this structure to fit more complex applications.