MVP

MVP

Skillson (Mindorks)

What is MVP?

MVP

It is an architecture that provides code reusability and testability. By following this architecture it will be easy to update code in future. To work within a team we need to follow any architecture for code readability.

Why MVP

If we can write code easily in activities then why we need to follow any architecture, at a point of time it is good that your application is working fine but how to make changes in your code in future if needed, how you test if required. Implementing changes after a period of time seems to be a mess in your own written code in any application, how other or new team members implement changes.

To work within a team, we need ease in code readability for every team members, updating codes with ease in future also needs to be handled efficiently, it can only be done by following some architecture.

To overcome with all these issues we should follow MVP, as MVP has all the solution.

MVP application is divided into three parts.

  1. Model
  2. View
  3. Presenter

Let's understand these components in next page.

---------------------------------------------------------------

Model, View, Presenter

android-mvp-concept-diagram

Model

It handles the data part of the application. It does not interact directly with the view. It provides data to Presenter, and presenter forwards data to the view and intake data from presenter which is provided by the view. Model is not even aware of view and vice versa.

Model is divided into various parts, at center we have datamanager which is the single part of the model with which the presenter interacts, then datamanager on further interacts with other components of the model.

View

It handles the presentation of the layout. Its responsibility is to draw ui with data as per the instructions provided by Presenter. Activities, fragment, dialogs, custom views are the view part of the application.

Each view has a presenter.

Base of the view has atleast two parts as MvpView and Activity, among them MvpView is an interface and Activity is a class which implements MvpView. Base part of the view can further be divided into various parts as per the use cases.

Presenter

It is a gateway between model and view as they do not interact each other directly. Every data passes through this gateway. It updates the view by taking the data from the model and update the model with data provided by the view.

Base of the presenter also have a minimum of two parts, among them first is MvpPresenter as interface and second is BasePresenter as class implementing this interface. It’s base part can also be divided into various parts as per the use case.

------------------------------------------------------

MVP Implementation

As we are starting to explore MVP, let’s learn with very basic MVP sample Android project.

What is in this sample app, how it works?

At very first, we are having SplashActivity as launcher activity, it’s only work is to decide which activity to open, if already logged in, open MainActivity otherwise open LoginActivity.

Then on LoginActivity we have two edittext one to input email and another to input password and a login button, by clicking on this we move to MainActivity by storing the email to SharedPreferences, on the MainActivity we are showing email in textview by extracting it from SharedPreferences and we are having logout button too on MainActivity, by clicking on this we again moved back to LoginActivity by clearing all the SharedPreferences data.

Github repo for the project

Now it’s time to implement MVP.

Step 1.

Create a new android studio project.

At very first, create the model part as MVP initials is model.

Model

SharedPrefsHelper

It is called only by datamanager. Presenter never directly interacts with SharedPrefsHelper.

public class SharedPrefsHelper {

    public static final String MY_PREFS = "MY_PREFS";

    public static final String EMAIL = "EMAIL";

    SharedPreferences mSharedPreferences;

    public SharedPrefsHelper(Context context) {
        mSharedPreferences = context.getSharedPreferences(MY_PREFS, MODE_PRIVATE);
    }

    public void clear() {
        mSharedPreferences.edit().clear().apply();
    }

    public void putEmail(String email) {
        mSharedPreferences.edit().putString(EMAIL, email).apply();
    }

    public String getEmail() {
        return mSharedPreferences.getString(EMAIL, null);
    }

    public boolean getLoggedInMode() {
        return mSharedPreferences.getBoolean("IS_LOGGED_IN", false);
    }

    public void setLoggedInMode(boolean loggedIn) {
        mSharedPreferences.edit().putBoolean("IS_LOGGED_IN", loggedIn).apply();
    }

}

DataManager

It is the only part of model that interacts with presenter and vice versa, for interaction among other parts of model and presenter, datamanager acts as a middleman.

public class DataManager {

    SharedPrefsHelper mSharedPrefsHelper;

    public DataManager(SharedPrefsHelper sharedPrefsHelper) {
        mSharedPrefsHelper = sharedPrefsHelper;
    }

    public void clear() {
        mSharedPrefsHelper.clear();
    }

    public void saveEmailId(String email) {
        mSharedPrefsHelper.putEmail(email);
    }

    public String getEmailId() {
        return mSharedPrefsHelper.getEmail();
    }

    public void setLoggedIn() {
        mSharedPrefsHelper.setLoggedInMode(true);
    }

    public Boolean getLoggedInMode() {
        return mSharedPrefsHelper.getLoggedInMode();
    }
}

Step 2.

Now its time to create base for view Part.

View

MvpView

It is an interface that is implemented by BaseActivity, it acts as a base view that is extended by all other view interfaces.

public interface MvpView {

}

BaseActivity

It is a base class for all activities, which implements MvpView and it is extended by all other activities in the application.

public class BaseActivity extends AppCompatActivity implements MvpView {

}

Step 3.

Create base for Presenter part.

Presenter

MvpPresenter

It is an interface that is implemented by BasePresenter, it acts as base presenter interface that is extended by all other presenter interfaces.

public interface MvpPresenter<V extends MvpView> {

    void onAttach(V mvpView);

}

BasePresenter

It is base class for all presenter that implements MvpPresenter and it is extended by all other presenters there in application.

public class BasePresenter<V extends MvpView> implements MvpPresenter<V> {

    private V mMvpView;

    DataManager mDataManager;


    public BasePresenter(DataManager dataManager){
        mDataManager = dataManager;
    }

    @Override
    public void onAttach(V mvpView) {
        mMvpView = mvpView;
    }

    public V getMvpView() {
        return mMvpView;
    }

    public DataManager getDataManager() {
        return mDataManager;
    }
}

As of now, we are done with creating base for MVP architecture. As we know MVP architecture is plug and play architecture, if we need anything more in base we can add or change that at any time, this is also the advantage of following MVP architecture.

-----------------------------------------------------------

Step 4.

In the previous page we were done with creating base for MVP architecture, it is time to create launcher activity of the app which is our SplashActivity.

First create interface for the view which extends MvpView.

SplashMvpView

public interface SplashMvpView extends MvpView {

    void openMainActivity();

    void openLoginActivity();

}

SplashActivity

After creating the interface, create the class for the view which extends BaseActivity and implements the interface we have for this view.

public class SplashActivity extends BaseActivity implements SplashMvpView {

    SplashPresenter mSplashPresenter;

    public static Intent getStartIntent(Context context) {
        Intent intent = new Intent(context, SplashActivity.class);
        return intent;
    }

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

        DataManager dataManager = ((MvpApp) getApplication()).getDataManager();

        mSplashPresenter = new SplashPresenter(dataManager);

        mSplashPresenter.onAttach(this);

        mSplashPresenter.decideNextActivity();

    }

    @Override
    public void openMainActivity() {
        Intent intent = MainActivity.getStartIntent(this);
        startActivity(intent);
        finish();
    }

    @Override
    public void openLoginActivity() {
        Intent intent = LoginActivity.getStartIntent(this);
        startActivity(intent);
        finish();
    }
}

As it is our launcher activity, make sure to change this as launcher activity in your AndroidManifest.

       <activity android:name=".ui.splash.SplashActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

SplashMvpPresenter

First create interface for the Presenter which extends MvpPresenter.

public interface SplashMvpPresenter<V extends SplashMvpView> extends MvpPresenter<V> {

    void decideNextActivity();

}

SplashPresenter

After creating the interface, create class for the presenter which extends BasePresenter and implements the interface we have for this presenter.

public class SplashPresenter<V extends SplashMvpView> extends BasePresenter<V> implements SplashMvpPresenter<V> {

    public SplashPresenter(DataManager dataManager) {
        super(dataManager);
    }

    @Override
    public void decideNextActivity() {
        if (getDataManager().getLoggedInMode()) {
            getMvpView().openMainActivity();
        } else {
            getMvpView().openLoginActivity();
        }
    }
}

Step 5.

What after SplashActivity ?

As per the app description, we need LoginActivity after SplashActivity.

CommonUtils

In the login activity we will be needing to verify email provided by users, following the architecture we can create this method in CommonUtils too.

public class CommonUtils {

    public static boolean isEmailValid(String email) {
        Pattern pattern;
        Matcher matcher;
        final String EMAIL_PATTERN =
                "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@"
                        + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
        pattern = Pattern.compile(EMAIL_PATTERN);
        matcher = pattern.matcher(email);
        return matcher.matches();
    }

}

LoginMvpView

public interface LoginMvpView extends MvpView {

    void openMainActivity();

    void onLoginButtonClick();

}

LoginActivity

public class LoginActivity extends BaseActivity implements LoginMvpView {

    LoginPresenter loginPresenter;

    EditText editTextEmail, editTextPassword;

    Button button;

    public static Intent getStartIntent(Context context) {
        Intent intent = new Intent(context, LoginActivity.class);
        return intent;
    }

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

        DataManager dataManager = ((MvpApp) getApplication()).getDataManager();
        loginPresenter = new LoginPresenter(dataManager);

        loginPresenter.onAttach(this);
        editTextEmail = (EditText) findViewById(R.id.editTextEmail);
        editTextPassword = (EditText) findViewById(R.id.editTextPassword);

        button = (Button) findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onLoginButtonClick();
            }
        });

    }

    @Override
    public void openMainActivity() {
        Intent intent = MainActivity.getStartIntent(this);
        startActivity(intent);
        finish();
    }

    @Override
    public void onLoginButtonClick() {

        String emailId = editTextEmail.getText().toString();
        String password = editTextPassword.getText().toString();

        if (!CommonUtils.isEmailValid(emailId)) {
            Toast.makeText(this, "Enter correct Email", Toast.LENGTH_LONG).show();
            return;
        }

        if (password == null || password.isEmpty()) {
            Toast.makeText(this, "Enter Password", Toast.LENGTH_LONG).show();
            return;
        }

        loginPresenter.startLogin(emailId);

    }
}

LoginMvpPresenter

public interface LoginMvpPresenter<V extends LoginMvpView> extends MvpPresenter<V> {

    void startLogin(String emailId);

}

LoginPresenter

public class LoginPresenter<V extends LoginMvpView> extends BasePresenter<V> implements LoginMvpPresenter<V> {

    public LoginPresenter(DataManager dataManager) {
        super(dataManager);
    }

    @Override
    public void startLogin(String emailId) {
        getDataManager().saveEmailId(emailId);
        getDataManager().setLoggedIn();
        getMvpView().openMainActivity();
    }

}

Step 6.

What after Logged in?Time to move on to MainActivity, now let’s create MainActivity.

MainMvpView

public interface MainMvpView extends MvpView {

    void openSplashActivity();

}

MainActivity

public class MainActivity extends BaseActivity implements MainMvpView {

    TextView textViewShow;
    Button buttonLogout;
    MainPresenter mainPresenter;

    public static Intent getStartIntent(Context context) {
        Intent intent = new Intent(context, MainActivity.class);
        return intent;
    }

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

        DataManager dataManager = ((MvpApp) getApplication()).getDataManager();
        mainPresenter = new MainPresenter(dataManager);
        mainPresenter.onAttach(this);

        textViewShow = (TextView) findViewById(R.id.textViewShow);

        buttonLogout = (Button) findViewById(R.id.buttonLogout);

        textViewShow.setText(mainPresenter.getEmailId());


        buttonLogout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mainPresenter.setUserLoggedOut();
            }
        });

    }

    @Override
    public void openSplashActivity() {
        Intent intent = SplashActivity.getStartIntent(this);
        startActivity(intent);
        finish();
    }
}

MainMvpPresenter

public interface MainMvpPresenter<V extends MainMvpView> extends MvpPresenter<V> {

    String getEmailId();

    void setUserLoggedOut();

}

MainPresenter

public class MainPresenter<V extends MainMvpView> extends BasePresenter<V> implements MainMvpPresenter<V> {

    public MainPresenter(DataManager dataManager) {
        super(dataManager);
    }

    @Override
    public String getEmailId() {
        return getDataManager().getEmailId();
    }

    @Override
    public void setUserLoggedOut() {
        getDataManager().clear();
        getMvpView().openSplashActivity();
    }

}

Step 7

MvpApp

public class MvpApp extends Application {

    DataManager dataManager;

    @Override
    public void onCreate() {
        super.onCreate();

        SharedPrefsHelper sharedPrefsHelper = new SharedPrefsHelper(getApplicationContext());
        dataManager = new DataManager(sharedPrefsHelper);

    }

    public DataManager getDataManager() {
        return dataManager;
    }

}

Step 8

Android Manifest

Now add the name of the class that is extending application class in the app to application part of AndroidManifest.

    <application
        android:name=".MvpApp"
    ......
    ......
    ......
    ......
    </application>

Step 9

Run your code, you are done with creating basic MVP sample app.

Check the complete project here

What next?

Refer the below links to learn how to build a complete MVP Android project.

  1. Essential Guide For Designing Your Android App Architecture: MVP: Part 1
  2. Android MVP Architecture Extension with Interactors and Repositories

If you want to explore MVVM, refer this link

https://github.com/MindorksOpenSource/android-mvvm-architecture


Report Page