Brief introduction
MVP stands for: Model-View-Presenter; MVP is evolved from the classic MVC pattern from, their basic ideas have in common places: Handling Controller / Presenter responsible for logic, Model provides data, View is responsible for displaying.
design diagram
advantage
1, M and V are completely separated, the coupling is reduced.
2, it can be used more efficiently Model, because all interactions are occurring within Presenter.
3, (Presener multiplexing) may be used for a plurality of views Presener (View), without changing the logical Presenter. Change the view (View) more frequently than change model (Model), it is so super convenient.
4, (View multiplexing) View of the components may be performed. Among the MVP, View not rely Model. This allows View spun off from a particular business scenario, it can be said View can be done on the business logic completely ignorant. It only needs to provide a range of interface to the upper layer operation. View so that you can make highly reusable components.
5, unit test easier.
Shortcoming
1, due to the rendering views on the Presenter, the View and Presenter view so that interaction would be too frequent. Especially in view of the need to modify the time, Presenter also need to follow the changes, a lot of trouble.
2, Presenter in addition to business logic, there are a lot of View-> Model, Model-> View the manual synchronization logic, resulting Presenter relatively heavy, it would be more difficult to maintain.
3, in fact, the whole structure is very clear, very clear business logic, low coupling, but it is to write their own troubles, Presenter bad maintenance, the workload is too big, too heavy, a bit like in MVC Activity, and responsibilities Too much.
Examples
1, Code
LoginInteractor.java
import android.os.Handler;
import android.text.TextUtils;
/**
* Created on 2019/4/1 16:11
*
* @author Gong
*/
public class LoginInteractor {
private Handler mHandler = new Handler();
interface OnLoginFinishedListener{
void onUsernameError();
void onPasswordError();
void onSuccess();
}
public void login(final String username, final String password, final OnLoginFinishedListener listener) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (TextUtils.isEmpty(username)) {
listener.onUsernameError();
return;
}
if (TextUtils.isEmpty(password)) {
listener.onPasswordError();
return;
}
listener.onSuccess();
}
},2000);
}
}
**LoginView.java**
<pre style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-size: inherit; color: inherit; line-height: inherit;">
/**
* Created on 2019/4/1 16:08
*
* @author Gong
*/
public interface LoginView {
void showProgress();
void hideProgress();
void setUserNameError();
void setPasswordError();
void navigateToHome();
}
**LoginPresenter.java**
<pre style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-size: inherit; color: inherit; line-height: inherit;">
/**
* Created on 2019/4/1 16:19
*
* @author Gong
*/
public class LoginPresenter implements LoginInteractor.OnLoginFinishedListener {
private LoginView mLoginView;
private LoginInteractor mLoginInteractor;
public LoginPresenter(LoginView loginView,LoginInteractor loginInteractor) {
this.mLoginView = loginView;
this.mLoginInteractor = loginInteractor;
}
public void validateCredentials(String username,String password) {
if (mLoginView != null) {
mLoginView.showProgress();
}
mLoginInteractor.login(username,password,this);
}
public void onDestroy() {
mLoginView = null;
}
@Override
public void onUsernameError() {
if (mLoginView != null) {
mLoginView.setUserNameError();
mLoginView.hideProgress();
}
}
@Override
public void onPasswordError() {
if (mLoginView != null) {
mLoginView.setPasswordError();
mLoginView.hideProgress();
}
}
@Override
public void onSuccess() {
if (mLoginView != null) {
mLoginView.navigateToHome();
}
}
}
LoginActivity.java
public class LoginActivity extends AppCompatActivity implements LoginView {
private ProgressBar mProgressBar;
private EditText mUserName,mPassword;
private LoginPresenter mPresenter;
private Button mLogin;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
mPresenter = new LoginPresenter(this,new LoginInteractor());
mLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
validateCredentials();
}
});
}
private void initView() {
mPassword = findViewById(R.id.password);
mUserName = findViewById(R.id.username);
mProgressBar = findViewById(R.id.progress);
mLogin = findViewById(R.id.login);
}
private void validateCredentials() {
mPresenter.validateCredentials(mUserName.getText().toString(),mPassword.getText().toString());
}
@Override
public void showProgress() {
mProgressBar.setVisibility(View.VISIBLE);
}
@Override
public void hideProgress() {
mProgressBar.setVisibility(View.GONE);
}
@Override
public void setUserNameError() {
mUserName.setError(getString(R.string.user_name_error));
}
@Override
public void setPasswordError() {
mPassword.setError(getString(R.string.password_error));
}
@Override
public void navigateToHome() {
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
@Override
protected void onDestroy() {
mPresenter.onDestroy();
super.onDestroy();
}
}
ic_username.xml
<?xml version="1.0" encoding="utf-8"?>
<vector android:height="24dp" android:tint="#666666"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>
ic_password.xml
<?xml version="1.0" encoding="utf-8"?>
<vector android:height="24dp" android:tint="#666666"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12.65,10C11.83,7.67 9.61,6 7,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6c2.61,0 4.83,-1.67 5.65,-4H17v4h4v-4h2v-4H12.65zM7,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
</vector>
strings.xml
<string name="user_name">请输入用户名</string>
<string name="password">请输入密码</string>
<string name="log_in">登录</string>
<string name="user_name_error">用户名输入错误</string>
<string name="password_error">密码输入错误</string>
activity_login.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="250dp"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:gravity="center"
android:orientation="vertical">
<EditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="8dp"
android:drawableStart="@drawable/ic_username"
android:gravity="center_vertical"
android:hint="@string/user_name"
android:inputType="text"
android:drawableLeft="@drawable/ic_username" />
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="8dp"
android:drawableStart="@drawable/ic_password"
android:gravity="center_vertical"
android:hint="@string/password"
android:inputType="textPassword"
android:drawableLeft="@drawable/ic_password" />
<Button
android:id="@+id/login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/log_in" />
<ProgressBar
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:visibility="gone" />
</LinearLayout>
2. renderings