Android MVP+RxJava+Retrofit (1) MVP设计模式

最近做项目都是接别人的二手项目,发现都是MVP设计模式,感觉自己欠下了2017年的技术债,所以有必要写一篇关于MVP设计模式的博客了,在写这篇博客之前,我想了挺久的,MVP这种文章一百度一大堆,也不知道自己写的怎么样,为了加深自己的理解也希望能帮助别人,这是我写文章的初衷。

说道MVP 那必须先说一下MVC

MVC设计模式

事件流向
Android MVP+RxJava+Retrofit (1) MVP设计模式_第1张图片

在 MVC 架构中,View 产生事件,通知到 Controller,Controller 中进行一系列逻辑处理,之后通知给 Model 去更新数据,Model 更新数据后,再将数据结构通知给 View 去更新界面.

优点: 结构清晰,职责划分清晰,降低耦合,有利于组件重用

缺点: Activity / Fragment 中代码较多,增加代码结构的复杂性.

但是在现实开发中 基本都把业务逻辑扔在了 Activity / Fragment 中 ,很少有人去写Controller.这种写法俗称一把梭.主要是因为开发进度紧能简单就简单,也不管什么代码耦合度的问题了.

MVP设计模式

不知道为啥很多人都在用MVP ,具体这东西哪里香 各有各的道理.个人觉得它的优势并不明显.

事件流向
Android MVP+RxJava+Retrofit (1) MVP设计模式_第2张图片优点: 结构清晰,职责划分清晰,模块间充分解耦,有利于组件的重用.
缺点: 会引入大量的接口,导致项目文件数量激增. 增大代码结构复杂性

MVP 和 MVC 最大的不同,就是 View 和 Model 不相互持有,都通过 Presenter 做中转。View 产生事件,通知给 Presenter,Presenter 中进行逻辑处理后,通知 Model 更新数据,Model 更新数据后,通知数据结构给 Presenter,Presenter 再通知 View 更新界面。

上实例

Android MVP+RxJava+Retrofit (1) MVP设计模式_第3张图片

就实现一个简单的登录操作.

如果嫌手动写model Presenter contract(MVP管理类) 麻烦可以借助工具去实现,这里推荐一个插件MVP Helper 非常好用
Android MVP+RxJava+Retrofit (1) MVP设计模式_第4张图片
使用的时候也很简单
Android MVP+RxJava+Retrofit (1) MVP设计模式_第5张图片
然后直接生成目录
Android MVP+RxJava+Retrofit (1) MVP设计模式_第6张图片
介绍完这插件该说一下MVP 业务代码的实现了

先从负责数据逻辑的Model层开始说起
(1) 创建用于保存用户信息的实体类 UserBean

public class UserBean {

    private String username;
    private String password;
    
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

(2) 结果回调接口OnLoginListener

public interface OnLoginListener {

    //登录成功的回调
    void loginSuccess(UserBean user);
    //登录失败的回调
    void loginFailed();
}

(3) 定义业务接口,在没有使用Contract 管理类的时候,都是把Model 接口单独定义的.但是这里不那样麻烦操作.View Model Presenter 直接定义在loginContract 接口管理类中

public interface loginContract {

    interface Model {
        void Login(String username, String password, OnLoginListener loginListener);
    }

    interface View {

        String getUserName();
        String getPassword();
        void clearUserName();
        void clearPassword();
        void showFail();
        void showLoading();
        void hideLoading();
        void toHomeActivity(UserBean user);
    }

    interface Presenter {

        void login();

        void clear();
    }
}

(4) 具体Model的实现类loginModel

public class loginModel implements loginContract.Model {

    @Override
    public void Login(final String username, final String password, final OnLoginListener loginListener) {
        //模拟网络请求耗时操作
        new Thread() {
            @Override
            public void run() {
                //模拟了耗时
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //模拟登录成功 账号 XXX 密码 000
                if ("XXX".equals(username) && "000".equals(password)) {
                    UserBean user = new UserBean();
                    user.setUsername(username);
                    user.setPassword(password);
                    loginListener.loginSuccess(user);
                } else {
                    loginListener.loginFailed();
                }
            }
        }.start();
    }
}

说完负责数据的Model层 接下来该说说Presenter了,我们知道是Presenter 把View 与Model 相互关联,然后进行逻辑的处理,处理之后在告知View 去更新UI.

注意作为View 与Model 两者之间的 中间人. Presenter必须要能拿到View和Model的实现类

public class loginPresenter implements loginContract.Presenter {
    
    private loginContract.View userLoginView;
    private loginModel loginModel;
    private Handler mHandler = new Handler();

    //对应视图页面销毁的标志位,当视图销毁后回调就不需要处理了
    private boolean destroyFlag;

    //Presenter必须要能拿到View和Model的实现类
    public loginPresenter(loginContract.View userLoginView) {
        this.userLoginView = userLoginView;
        this.loginModel = new loginModel();
    }


    @Override
    public void login() {
        userLoginView.showLoading();
        loginModel.Login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener() {
            @Override
            public void loginSuccess(final UserBean user) {
                if (!destroyFlag) { //View层销毁后不需要处理的判断
                    //需要在UI线程执行
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            userLoginView.toHomeActivity(user);
                            userLoginView.hideLoading();
                        }
                    });
                }
            }

            @Override
            public void loginFailed() {
                if (!destroyFlag) { //View层销毁后不需要处理的判断
                    //需要在UI线程执行
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            userLoginView.showFail();
                            userLoginView.hideLoading();
                        }
                    });
                }
            }
        });
    }

    @Override
    public void clear() {
        userLoginView.clearUserName();
        userLoginView.clearPassword();
    }
    
    //解绑视图
    public void detachView() {
        destroyFlag = true;
        this.userLoginView = null;
    }
}

最后我们再说一下View 层先看一下代码

public class LoginActivity extends AppCompatActivity implements loginContract.View {


    private loginPresenter presenter;
    private EditText etUserName;
    private EditText etPassword;
    private LoadingDialog loadingDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        presenter = new loginPresenter(this);
        initView();


    }

    private void initView() {
        Button btnLogin = findViewById(R.id.btn_login);
        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.login();
            }
        });
        Button btnClean = findViewById(R.id.btn_clean);
        btnClean.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.clear();
            }
        });
        etUserName = findViewById(R.id.et_user_name);
        etPassword = findViewById(R.id.et_password);
        loadingDialog = new LoadingDialog(LoginActivity.this, "加载中...");

    }


    @Override
    public String getUserName() {
        return etUserName.getText().toString();
    }

    @Override
    public String getPassword() {
        return etPassword.getText().toString();
    }

    @Override
    public void clearUserName() {
        etUserName.setText("");

    }

    @Override
    public void clearPassword() {
        etPassword.setText("");
    }

    @Override
    public void showFail() {
        Toast.makeText(this, "登录失败", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showLoading() {
        loadingDialog.show();
    }

    @Override
    public void hideLoading() {
        loadingDialog.dismiss();
    }

    @Override
    public void toHomeActivity(UserBean user) {
        Toast.makeText(this, "跳转到登录成功页面", Toast.LENGTH_SHORT).show();
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //为了防止内存泄漏,解绑Presenter层对View层的引用
        presenter.detachView();
    }
}

总结一下
MVP设计模式 在activity Fragment 中处理数据更新数据的方式进行解耦,在Presenter 中 View 与 Model 进行逻辑处理. 而数据的处理 在Model 中进行操作. 这样去做结构明了.但是弊端也是有的 目录层级过多,代码量增大.

最近接手的项目 我发现很多人,把Model 层处理数据(网络请求)这部分放在了Presenter 层中进行处理.
比如

public class EditAddressContact {
    public interface View extends BaseContact.BaseView {
        void showError(String msg);

        void Success();

        void showCityList(List<LianDongBean.ResultBean> result);

        void deleteSuccess();
    }

    public interface presenter {
        void AddAddress(int city_id, int county_id, String ua_detail);
        }

这样

public class EditAddressPresenter extends RxPresenter<EditAddressContact.View> implements EditAddressContact.presenter {
    @Inject
    public EditAddressPresenter() {
    }


    @Override
    public void AddAddress( int city_id, int county_id,String ua_detail) {
        OkGo.<LianDongBean>post(Constant.IP + Constant.addaddress)
                .params("token", PreferenceManager.getInstance().getToken())
                .params("city_id", city_id)
                .params("county_id", county_id)
                .params("ua_detail", ua_detail)
                .execute(new JsonCallback<LianDongBean>() {
                    @Override
                    protected void onVerifySuccess(Response<LianDongBean> response) {
                        if (response.body().getStatus() == 0) {
                            view.Success();
                        } else view.showError(response.body().getMsg());
                    }

                    @Override
                    public void onError(Response<LianDongBean> response) {
                        super.onError(response);
                        view.showError(handleError(response.getException()));
                    }
                });
    }
    
  }

这种我不能说这种不好,总之一切为了业务方便而定 =_= !

你可能感兴趣的:(Android基础)