一、MVP介绍
-
MVP的架构组成如图1所示
相对于MVC架构,MVP架构对应的内容有了如下调整:
- V层对应Activity和Fragment,或者自定义的View。
- P层需要自己创建,用来处理业务逻辑。
- M层同MVC的M,也是需要自己创建的,用来处理数据。
二、 MVP的优点、缺点、适用范围
1. 优点
MVP对MVC的缺点做了很大的改进
1)明确了各个层级的职责范围View层改为Activity和Fragment,只负责UI的更新。Presenter层的角色变成Controller,只负责业务逻辑的处理。Model层跟MVC架构中的Model层一样,负责底层功能模块的实现。
2)避免了跨层级的交互
View层只和Presenter层交互,Presenter层只和Model层交互,而且层级间的交互只能通过接口进行,避免了View层直接接触Model层的可能。
3)Presenter不一定对应一个固定的View,其他的View也可以使用Presenter
由于Presenter暴露出去的是接口,所以Presenter层同样可以用来进行业务逻辑的单元测试。
2. 缺点
- 由于层之间是通过接口实现访问的,故而会增加不少的接口。
- 会造成从View层直到Model层使用到的类会比较多,流程不是那么地直观。
3. 适用范围
- 适合项目功能较多、版本迭代频繁、人员分工明确的App
三、MVP实例(登陆功能为例)
1.布局文件
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".mvp.view.LoginMainActivity">
<EditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
app:layout_constraintTop_toBottomOf="@+id/username"
app:layout_constraintLeft_toLeftOf="parent"/>
<Button
android:id="@+id/login"
android:text="登陆"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
app:layout_constraintTop_toBottomOf="@+id/password"
app:layout_constraintLeft_toLeftOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
2.根据需求创建View层接口:ILoginView
public interface ILoginView {
void onShowMessage(String msg);
}
3.根据需求创建Presenter层接口:ILoginPresenter
public interface ILoginPresenter {
void login(String username, String password);
}
4.在Model层创建User类
public class User {
public boolean isValid(String username, String password) {
if (username != null && !username.isEmpty() && password != null && !password.isEmpty()) {
return true;
}
return false;
}
}
5.创建LoginPresenterImpl类实现ILoginPresenter
public class LoginPresenterImpl implements ILoginPresenter{
private ILoginView mLoginView;
private User mUser;
public LoginPresenterImpl(ILoginView loginView) {
mLoginView = loginView;
mUser = new User();
}
@Override
public void login(String username, String password) {
boolean isValid = mUser.isValid(username, password);
if (isValid) {
mLoginView.onShowMessage("login success");
} else {
mLoginView.onShowMessage("login failed");
}
}
}
6.创建对应的LoginMainActivity类
public class LoginMainActivity extends AppCompatActivity implements ILoginView, View.OnClickListener {
ILoginPresenter loginPresenter = new LoginPresenterImpl(this);
private EditText mUsername;
private EditText mPassword;
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login_main);
mUsername = findViewById(R.id.username);
mPassword = findViewById(R.id.password);
mButton = findViewById(R.id.login);
mButton.setOnClickListener(this);
}
@Override
public void onShowMessage(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.login) {
loginPresenter.login(mUsername.getText().toString(), mPassword.getText().toString());
}
}
}
整体的目录结构如下: