参考文章:浅谈 MVP in Android_Hongyang-CSDN博客_android mvp; 本文出自:【张鸿洋的博客】
首先,MVP包括三层
M层指model:专门用于处理数据逻辑,类似于MVC中的M,像service,dao层之类的这些。
V层指View:处理视图层的一些控件的展示和隐藏等,负责View的绘制及与用户的交互,对应的实现就是Activity.类似于MVC中的V,html,jsp之类的
P层指Presenter:连接M层和V层,类似于MVC中的C,controller
贴代码详细介绍一下:
先看看布局文件吧
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="15dp">
<EditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="用户名"
android:textSize="18sp"
android:textColor="#000"/>
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="密码"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp">
<Button
android:id="@+id/login"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="登陆"
android:textSize="20sp" android:layout_marginRight="5dp"/>
<Button
android:id="@+id/clear"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="清除"
android:textSize="20sp"
android:layout_marginLeft="5dp"/>
</LinearLayout>
<ProgressBar
android:id="@+id/progressbar"
android:visibility="invisible"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
bean包下的实体类
package com.example.mvptest1.bean;
/**
* com.example.mvptest1.bean
*
* @author yueqingh
* @date 2021/9/29
*/
public class User {
private int uid;
private String name;
private String password;
public User() {
}
public User(String name, String password) {
this.name = name;
this.password = password;
}
public User(int uid, String name, String password) {
this.uid = uid;
this.name = name;
this.password = password;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"uid=" + uid +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}
model下的接口:因为model层是处理数据逻辑的,所以,定义了
public void login(String name,String password,OnLoginListener loginListener);这个方法,根据这个方法去判断登陆是否成功,所以又定义了一个内部接口OnLoginListener,内部接口中定义了两个方法,分别代表登陆成功和登陆失败
package com.example.mvptest1.model;
import com.example.mvptest1.bean.User;
/**
* com.example.mvptest1.model
*
* @author yueqingh
* @date 2021/9/29
*/
public interface UserLoginModel {
interface OnLoginListener{
void loginSuccess(User user);
void loginFailed();
}
public void login(String name,String password,OnLoginListener loginListener);
}
来看看model的实现吧,这里是没有对loginSuccess(User user)和loginFailed()进行实现的,因为登陆成功有一些view方面的东西需要实现,但是model又必须要和view分开,所以这里没有实现,将这两个方法交给了presenter去实现,因为presenter是连接model和view的。
package com.example.mvptest1.model.Impl;
import com.example.mvptest1.bean.User;
import com.example.mvptest1.model.UserLoginModel;
/**
* com.example.mvptest1.model.Impl
*
* @author yueqingh
* @date 2021/9/29
*/
public class UserLoginModelImpl implements UserLoginModel {
@Override
public void login(final String name, final String password, final OnLoginListener loginListener) {
//模拟子线程耗时操作
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//模拟登陆成功
if ("zhangsan".equals(name) && "admin".equals(password)){
User user = new User();
user.setName(name);
user.setPassword(password);
loginListener.loginSuccess(user);
}else {
loginListener.loginFailed();
}
}
}).start();
}
}
model层看完了,我们看看view层,首先看看view层的接口,可以看到这个接口全都是与最前面的布局相关的,也就是view,没有涉及到数据逻辑。
package com.example.mvptest1.view;
import com.example.mvptest1.bean.User;
/**
* com.example.mvptest1.view
*
* @author yueqingh
* @date 2021/9/29
*/
public interface UserLoginView {
//获取输入的用户名
String getUsername();
//获取输入的密码
String getPassword();
//显示进度条
void showProgress();
//隐藏进度条
void hideProgress();
//清除用户名的输入
void clearUsername();
//清楚密码的输入
void clearPassword();
//登陆成功的显示,用于项目的时候这里就可以用于Activity的跳转
void toMainActivity(User user);
//登陆失败的提示信息显示
void showFailedError();
}
View的实现是在对应的Activity中实现的,但是我们要先把view和model的关系先建立起来,所以看一下代码
package com.example.mvptest1.presenter;
/**
* com.example.mvptest1.presenter
*
* @author yueqingh
* @date 2021/9/29
*/
public interface UserLoginPresenter {
//登陆
void login();
//清除
void clear();
}
presenter的实现
package com.example.mvptest1.presenter.Impl;
import android.os.Handler;
import com.example.mvptest1.bean.User;
import com.example.mvptest1.model.UserLoginModel;
import com.example.mvptest1.presenter.UserLoginPresenter;
import com.example.mvptest1.view.UserLoginView;
/**
* com.example.mvptest1.presenter.Impl
*
* @author yueqingh
* @date 2021/9/29
*/
public class UserLoginPresenterImpl implements UserLoginPresenter {
//view
private UserLoginView userLoginView;
//model
private UserLoginModel userLoginModel;
private Handler handler = new Handler();
//构造函数
public UserLoginPresenterImpl(UserLoginView userLoginView, UserLoginModel userLoginModel) {
this.userLoginView = userLoginView;
this.userLoginModel = userLoginModel;
}
/**
* 在点击登陆按钮时会调用这个方法,然后到model中处理数据逻辑,在view中进行对应的显示和隐藏
*/
@Override
public void login() {
userLoginModel.login(userLoginView.getUsername(), userLoginView.getPassword(), new UserLoginModel.OnLoginListener() {
@Override
public void loginSuccess(final User user) {
//需要在UI线程执行
handler.post(new Runnable() {
@Override
public void run() {
userLoginView.toMainActivity(user);
userLoginView.hideProgress();
}
});
}
@Override
public void loginFailed() {
handler.post(new Runnable() {
@Override
public void run() {
userLoginView.showFailedError();
userLoginView.showProgress();
}
});
}
});
}
/**
* 点击清除按钮时,直接调用view的方法
*/
@Override
public void clear() {
userLoginView.clearUsername();
userLoginView.clearPassword();
}
}
最后一步了,model的数据逻辑处理已经处理完毕,view的接口也建立完毕,再然后,model和view的关联也已经建立完毕,接下下我们就处理一些view的实现,在Activity中去调用presenter。
package com.example.mvptest1;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.example.mvptest1.bean.User;
import com.example.mvptest1.model.Impl.UserLoginModelImpl;
import com.example.mvptest1.presenter.Impl.UserLoginPresenterImpl;
import com.example.mvptest1.presenter.UserLoginPresenter;
import com.example.mvptest1.view.UserLoginView;
public class MainActivity extends AppCompatActivity implements UserLoginView, View.OnClickListener {
private EditText usernameEt;
private EditText passwordEt;
private Button loginBtn;
private Button clearBtn;
private ProgressBar progressBar;
//presenter
private UserLoginPresenter userLoginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
usernameEt = findViewById(R.id.username);
passwordEt = findViewById(R.id.password);
loginBtn = findViewById(R.id.login);
clearBtn = findViewById(R.id.clear);
progressBar = findViewById(R.id.progressbar);
loginBtn.setOnClickListener(this);
clearBtn.setOnClickListener(this);
userLoginPresenter = new UserLoginPresenterImpl(this, new UserLoginModelImpl());
}
@Override
public String getUsername() {
return usernameEt.getText().toString();
}
@Override
public String getPassword() {
return passwordEt.getText().toString();
}
@Override
public void showProgress() {
progressBar.setVisibility(View.VISIBLE);
}
@Override
public void hideProgress() {
progressBar.setVisibility(View.GONE);
}
@Override
public void clearUsername() {
usernameEt.setText("");
}
@Override
public void clearPassword() {
passwordEt.setText("");
}
@Override
public void toMainActivity(User user) {
Toast.makeText(MainActivity.this,"loginSuccess",Toast.LENGTH_SHORT).show();
}
@Override
public void showFailedError() {
Toast.makeText(MainActivity.this,"loginFailed",Toast.LENGTH_SHORT).show();
}
//根据id判断点击的是哪一个按钮
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.login:
userLoginPresenter.login();
break;
case R.id.clear:
userLoginPresenter.clear();
break;
default:
break;
}
}
}
好了,就介绍到这里,写这个东西主要是为了后面回顾,这是我看了张鸿洋大佬的博客和其他很多人的博客最后的总结吧,代码几乎与张鸿洋的一致,没有特别大的改动,因为这个例子确实很生动,易懂,如有理解不到位的地方还请指正,如有侵权的地方,还请联系,立删
|