目录
1)MVP简介
2)MVP实例
1)MVP简介
MVP模式将Activity中的业务逻辑全部剥离出来,Activity只做UI部分的处理,所有业务逻辑层由Presenter层去处理。
分层 | 说明 |
---|---|
View | Activity,Fragment,负责处理UI |
Presenter | 业务逻辑层,既能调用UI,又能请求数据源 |
Model | 纯业务数据源的接口与实现 |
M层与V层无法直接通信,需要通过P层处理。
2)MVP实例
假设我们来实现一个登录请求。
-定义实体Bean
public class LoginReq {
private String username;
private String password;
...
}
public class LoginResponse {
private String retcode;
private String retinfo;
private UserData userData;
...
}
public class UserData {
private String name;
private String age;
...
}
-Model层
- Callback接口, 是Model给Presenter反馈数据信息的载体,需要在Callback中定义数据的各种反馈状态
//通过泛型T表示接受任意类型
public interface MvpCallback<T> {
/**
* 数据请求成功
* @param data 请求到的数据
*/
void onSuccess(T data);
/**
* 使用网络API接口请求方式时,虽然已经请求成功但是由
* 于{@code msg}的原因无法正常返回数据。
*/
void onFail(T data);
/**
* 请求数据失败,指在请求网络API接口请求方式时,出现无法联网、
* 缺少权限,内存泄露等原因导致无法连接到请求数据源。
*/
void onError();
/**
* 当请求数据结束时,无论请求结果是成功,失败或是抛出异常都会执行此方法给用户做处理,通常做网络
* 请求时可以在此处隐藏“正在加载”的等待控件
*/
void onComplete();
}
- 登录业务接口,这里采用了ARouter-IProvider的服务依赖注入的方式去解耦服务,如不需要可不用继承IProvider
public interface ILoginBiz extends IProvider {
//登录操作
void login(LoginReq req, MvpCallback mvpCallback);
//存储登录信息
void saveUserdata(UserData userdata);
}
- 登录业务实现,
@Route(path = "/service/login", name="登录服务")
public class LoginBiz implements ILoginBiz {
@Override
public void login(LoginReq req, final MvpCallback mvpCallback) {
Map<String,String> param = new HashMap<String, String>();
//调用公共组件库的OkHttpUtil进行网络API请求
OkHttpUtil.sendRequestPost(param, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//模拟2秒休眠
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//回调onComplete
mvpCallback.onComplete();
//模拟response数据
UserData userData = new UserData("涂高峰","18");
LoginResponse loginResponse = new LoginResponse("000000","登录成功",userData);
//回调onSuccess
mvpCallback.onSuccess(loginResponse.getUserData());
}
});
}
@Override
public void saveUserdata(UserData userdata) {
}
@Override
public void init(Context context) {
}
}
-View层,View接口是Activity层和Presenter层的中间层,它用于根据具体业务需要,为Presenter层提供调用Activity中具体UI操作的方法。
- IMvpView,抽象出的公共View
public interface IMvpView {
/**
* 显示正在加载view
*/
void showLoading();
/**
* 关闭正在加载view
*/
void hideLoading();
/**
* 显示提示
* @param msg
*/
void showToast(String msg);
}
- ILoginView,登录业务View,继承了IMvpView。
public interface ILoginView extends IMvpView {
/**
* 登录请求成功提示
*/
void loginSuccess(UserData userData);
/**
* 登录请求失败提示
*/
void loginFail(String text);
}
-Presenter层,具体的业务逻辑处理Java类,不含任何Android-API操作,负责请求数据源,并对数据源反馈做处理。
- MvpPresenter,抽象出公共的Presenter,
public class MvpPresenter<V extends IMvpView> {
/**
* 绑定的view
*/
private V mvpView;
/**
* 绑定view,一般在初始化中调用该方法
*/
public void attachView(V view){
this.mvpView = view;
}
/**
* 断开view,一般在onDestroy中调用
* 对于Activity异常销毁导致mvpView空指针
* 采用attachView和detachView,将view与activity生命周期绑定
*/
public void detachView(){
this.mvpView = null;
}
/**
* 是否与View建立连接
* 每次调用业务请求的时候都要出先调用方法检查是否与View建立连接
*/
public boolean isViewAttached(){
return this.mvpView != null;
}
/**
* 获取连接的view
*/
public V getView(){
return this.mvpView;
}
/**
* 获取连接的view名称
*/
public String getViewName(){
return this.mvpView.getClass().getSimpleName();
}
}
- LoginPresenter,登录业务Presenter,继承了MvpPresenter。
public class LoginPresenter extends MvpPresenter<ILoginView> {
//依赖注入发现服务
@Autowired(name = "/service/login")
LoginBiz loginBiz;
public LoginPresenter() {
// this.loginBiz = new LoginBiz();
//依赖注入
ARouter.getInstance().inject(this);
}
public void login(LoginReq req){
if (!isViewAttached()){
//如果没有View引用就不加载数据
return;
}
getView().showLoading();
loginBiz.login(req, new MvpCallback() {
@Override
public void onSuccess(final Object data) {
if (isViewAttached()){
MainLooper.runOnUiThread(new Runnable() {
@Override
public void run() {
getView().loginSuccess((UserData) data);
}
});
}
}
@Override
public void onFail(Object data) {
}
@Override
public void onError() {
}
@Override
public void onComplete() {
if (isViewAttached()){
MainLooper.runOnUiThread(new Runnable() {
@Override
public void run() {
getView().hideLoading();
}
});
}
}
});
}
}
-Activity,登录业务Activity,实现了ILoginView
public class MainActivity extends AppCompatActivity implements ILoginView,View.OnClickListener{
private LoginPresenter loginPresenter;
private TextView txt;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt = findViewById(R.id.txt);
progressBar = findViewById(R.id.progressBar);
findViewById(R.id.success_btn).setOnClickListener(this);
//初始化Presenter
loginPresenter = new LoginPresenter();
//绑定View引用
loginPresenter.attachView(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
//断开View引用
loginPresenter.detachView();
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.success_btn:
LoginReq loginReq = new LoginReq("tgf","123");
loginPresenter.login(loginReq);
break;
}
}
@Override
public void showLoading() {
progressBar.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading() {
progressBar.setVisibility(View.GONE);
}
@Override
public void showToast(String msg) {
Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
}
@Override
public void loginSuccess(UserData userData) {
txt.setText("姓名: "+userData.getName() + "年龄"+ userData.getAge());
}
@Override
public void loginFail(String text) {
}
}
-其他工具类
public class MainLooper extends Handler {
private static MainLooper instance = new MainLooper(Looper.getMainLooper());
protected MainLooper(Looper looper) {
super(looper);
}
public static MainLooper getInstance() {
return instance;
}
public static void runOnUiThread(Runnable runnable) {
if(Looper.getMainLooper().equals(Looper.myLooper())) {
runnable.run();
} else {
instance.post(runnable);
}
}
}