Implementation of MVP in Android Development
Category Programming Techniques
Recently, I wanted to refactor the code because the project needs to be used by several schools, and each school has a different interface, but the functionality is almost identical. Although using Gradle's branches can achieve the difference in code, the logic of the common part of the code is also increasing. So I wanted to refactor it. I recently looked at the MVP pattern, which is quite popular, and thought it was very suitable. However, there are many materials on the internet that are copied and some even have errors. I wanted to describe the MVP pattern according to my own understanding to facilitate others' understanding. Let's start with the MVC design pattern that everyone is most familiar with.
The MVC pattern decouples the M layer and the V layer, and the M layer and the V layer interact through the C layer.
Then let's take a look at MVP. The words that start with I in the following text are interfaces (typing the picture is so tiring...)
The biggest difference between MVP and MVC is that the P layer replaces the previous C layer, and it no longer controls the specific implementation but the interface. This way, whether it is multi-person development or frequent UI changes, it will not affect the P layer. As long as the interfaces of C and V layers do not change, the UI changes only need to change the implementation of the V layer, and the implementation of the C layer does not need to be changed. In this way, the code is very clear and convenient for testing, because the logic layer and the view layer are completely separated. Let's talk about it with the code below, still starting with the MVC pattern, using the login example. Android has already separated the C layer and the V layer very well. The XML we write is equivalent to the V layer, and the Activity is equivalent to the C layer.
public interface ICallback {
void receive(boolean success);
}
public class LoginModel {
public void login(String name, String password, ICallback callback) {
WebApi.login(name, password, callback);
}
}
public class LoginActivity extends Activity {
private LoginModel mLoginModel;
private EditText mUserNameEt;
private EditText mPasswordEt;
private Button mSubmitBtn;
public void onCreate(......) {
mLoginModel = new LoginModel(...);
mSubmitBtn.setOnClickListener(new OnClickListener(View view) {
mLoginModel.login(mUserNameEt.get..., mPasswordEt.get..., new ICallback() {
public void receive(boolean success) {
if (success) {
startActivity(new Intent(this, MainActivity.class));
finish();
} else {
Toast.makeText(this, "Login failed", Toast.LENGTH_SHORT).show();
}
}
});
});
}
}
Let's take a look at how to write it using the MVP pattern. There are comments below the article that say to write a contract class. I looked it up, and writing a contract class is more convenient, so the following code is the one I have modified.
public interface ILoginContract {
public interface ILoginModel {
public void login(String name, String password, ICallback callback);
}
public interface ILoginPresenter {
public void login(String name, String password);
}
public interface ILoginView {
public void showDialog();
public void dismissDialog();
public void showToast(String message);
public void navigateToMain();
}
}
public class PresenterImpl implements ILoginPresenter, ICallback {
private ILoginView mLoginView;
private ILoginModel mLoginModel;
public PresenterImpl(ILoginView loginView) {
this.mLoginView = loginView;
this.mLoginModel = new LoginModelImpl();
}
public void login(String name, String password) {
if (isEmpty(name) || isEmpty(password)) {
this.mLoginView.showToast("Username or password cannot be empty");
return;
}
this.mLoginModel.login(name, password, this);
}
public void receive(boolean success) {
if (success) {
this.mLoginView.navigateToMain();
} else {
this.mLoginView.showToast("Login failed");
}
}
private boolean isEmpty(String text) {
return text == null || "".equals(text) ? true : false;
}
}
```java public class LoginActivity extends Activity implements ILoginView { private IPresenter mPresenter; private EditText mUserNameEt; private EditText mPasswordEt; private Button mSubmitBtn; public void onCreate(......) { mPresenter = new PresenterImpl(this); mSubmitBtn.setOnClickListener(new OnClickListener(View view) { mPresenter.login(mUserNameEt.getText().toString(),