Recently I wanted to refactor the code because the project needs to be used by several schools, and each school's UI is different, but the functionality is almost identical. Although using Gradle branches can handle the code differences, the code logic in the common parts keeps growing, so I wanted to refactor. I took a look at the recently popular MVP pattern and found it very suitable. However, much of the material online is just copied around, and some even contains errors, so I wanted to describe the MVP pattern based on my own understanding to make it easier for others to grasp. First, let's talk about the MVC design pattern that everyone is most familiar with.

The MVC pattern decouples the M layer and the V layer; the M layer and V layer interact through the C layer.
Now let's look at MVP. In my text below, names starting with I mean interfaces (hand-drawing the diagram is tiring...)
The biggest difference between MVP and MVC is that the P layer replaces the former C layer and no longer controls specific implementations but interfaces. In this way, neither multi-developer development nor frequent UI changes will affect the P layer. As long as the interfaces of the C and V layers remain unchanged, UI changes only require modifying the V layer implementation; the C layer implementation doesn't even need to be changed. This keeps the code very clear and makes testing easy, because the logic layer and the view layer are completely separated. Let me use code to speak—starting with the MVC pattern, using login as an example. Android already separates the C layer and V layer 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,"登录失败",Toast.LENGTH_SHORT).show();
}
}
});
});
}
}
Let's look at how to write it with the MVP pattern. A comment below the article mentioned writing a contract class. I looked into it, and writing a contract class is indeed more convenient, so the code below is what I revised.
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("用户名或密码不能为空");
return;
}
this.mLoginModel.login(name,password,this);
}
public void receive(boolean success){
if(success){
this.mLoginView.navigateToMain();
}else{
this.mLoginView.showToast("登录失败");
}
}
private boolean isEmpty(String text){
return text==null||"".equals(text)?true:false;
}
}
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(),
mPasswordEt.getText().toString());
});
}
public void showDialog(){
//显示一个转圈的dialog;
}
public void dismissDialog(){
//隐藏转圈的dialog;
}
public void showToast(String message){
Toast.makeText(this,message,Toast.LENGTH_SHORT).show();
}
public void navigateToMain(){
startActivity(new Intent(this,MainActivity.class));
finish();
}
}
The MVP pattern does require more classes and code, but it is definitely worth it. You can see that the code logic is clearer to write than in the MVC pattern, and code testing is also simpler. You can even complete features when you only have the functionality and no UI mockups, and UI changes won't affect any business code.
The above MVP design pattern is my personal understanding. If there are any errors, please correct me. Thank you. Let's discuss and improve together.
Submitted by: oDynamicSupermano