Android 中 MVC 的简单理解https://blog.csdn.net/qq_17798399/article/details/95933628

MVP模式

相信大家对MVC都是比较熟悉了:M-Model-模型、V-View-视图、C-Controller-控制器,MVP作为MVC的演化版本,那么类似的MVP所对应的意义:M-Model-模型、V-View-视图、P-Presenter-表示器。 从MVC和MVP两者结合来看,Controlller/Presenter在MVC/MVP中都起着逻辑控制处理的角色,起着控制各业务流程的作用。而 MVP与MVC最不同的一点是M与V是不直接关联的也是就Model与View不存在直接关系,这两者之间间隔着的是Presenter层,其负责调控 View与Model之间的间接交互,MVP的结构图如下所示,对于这个图理解即可而不必限于其中的条条框框,毕竟在不同的场景下多少会有些出入的。在 Android中很重要的一点就是对UI的操作基本上需要异步进行也就是在MainThread中才能操作UI,所以对View与Model的切断分离是 合理的。此外Presenter与View、Model的交互使用接口定义交互操作可以进一步达到松耦合也可以通过接口更加方便地进行单元测试。

 

Android MVP 架构介绍_第1张图片

Model:业务逻辑和实体模型,用来操作实际的数据,包含Bean和Model的抽象接口来降低耦合。

View:就是Android中的视图,需要建立一个View的抽象接口View Interface。通过实现View的接口来实现View与Presenter的交互,从而降低耦合。对应于Activity,负责View的绘制与用户交互;

Presenter:View和Model的中间枢纽,处理和用户交互的逻辑。

为什么要用MVP?

其实我们日常开发中的Activity,Fragment和XML界面就相当于是一个 MVC 的架构模式,Activity中不仅要处理各种 UI 操作还要请求数据以及解析。

这种开发方式的缺点就是业务量大的时候一个Activity 文件分分钟飙到上千行代码,想要改一处业务逻辑光是去找就要费半天劲,而且有点地方逻辑处理是一样的无奈是不同的 Activity 就没办法很好的写成通用方法。

那 MVP 为啥好用呢?

MVP 模式将Activity 中的业务逻辑全部分离出来,让Activity 只做 UI 逻辑的处理,所有跟Android API无关的业务逻辑由 Presenter 层来完成。

将业务处理分离出来后最明显的好处就是管理方便,但是缺点就是增加了代码量。


MVP框架的搭建

MVP快速生成类的插件: https://github.com/githubwing/MVPHelper

Android MVP 架构介绍_第2张图片

下面演示下登陆的MVP实现方式:

(示例代码由开发项目中剥离到Demo中,登陆接口使用的是玩安卓的登陆API:http://www.wanandroid.com/blog/show/2)

首先,创建一个登陆的Contract:public interface MainContract {    interface Model { }    interface View extends BaseView { }    interface Presenter { }}其次创建Presenter、Model、View 对应Contract中的接口;public class MainPresenter implements  MainContract.Presenter{} public class MainModel implements MainContract.Model{}public class MainActivity  implements MainContract.View {}

 完整的Contract:

public interface MainContract {    interface Model {        Flowable> login(String username, String password);    }    interface View extends BaseView {        @Override        void showLoading();        @Override        void hideLoading();        @Override        void onError(Throwable throwable);        void onSuccess(BaseObjectBean bean);    }    interface Presenter {        /**         * 登陆         *         * @param username         * @param password         */        void login(String username, String password);    }}

在MainContract 中
Model接口 创建对应的联网请求的方法,将Presenter提交的字段放到联网请求中,发送给服务器
View 接口 创建在界面上显示加载中、取消加载以及登陆成功、失败的方法
Presenter 接口 创建 登陆的方法,以及需要提交的字段 (username、password)

MainModel的完整代码:

public class MainModel  implements MainContract.Model {    @Override    public Flowable> login(String username, String password) {        return RetrofitClient.getInstance().getApi().login(username,password);    }}

 

Model类实现MainContract.Model 接口中的 login(String username, String password)方法,将username、password放在联网请求中,进行请求服务器。

MainView 的完整代码:

public class MainActivity extends BaseMvpActivity implements MainContract.View {    @BindView(R.id.et_username_login)    TextInputEditText etUsernameLogin;    @BindView(R.id.et_password_login)    TextInputEditText etPasswordLogin;    @Override    public int getLayoutId() {        return R.layout.activity_main;    }    @Override    public void initView() {        mPresenter = new MainPresenter();        mPresenter.attachView(this);    }    /**     * @return 帐号     */    private String getUsername() {        return etUsernameLogin.getText().toString().trim();    }    /**     * @return 密码     */    private String getPassword() {        return etPasswordLogin.getText().toString().trim();    }    @Override    public void onSuccess(BaseObjectBean bean) {        Toast.makeText(this, bean.getErrorMsg(), Toast.LENGTH_SHORT).show();    }    @Override    public void showLoading() {        ProgressDialog.getInstance().show(this);    }    @Override    public void hideLoading() {        ProgressDialog.getInstance().dismiss();    }    @Override    public void onError(Throwable throwable) {    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // TODO: add setContentView(...) invocation        ButterKnife.bind(this);    }    @OnClick(R.id.btn_signin_login)    public void onViewClicked() {        if (getUsername().isEmpty() || getPassword().isEmpty()) {            Toast.makeText(this, "帐号密码不能为空", Toast.LENGTH_SHORT).show();            return;        }        mPresenter.login(getUsername(), getPassword());    }}

MainActivity 中实现 MainContract.View中的方法 ,在实现的方法中,进行进度条加载、和登陆成功or失败的UI的展示:

        @Override        void showLoading();        @Override        void hideLoading();        @Override        void onError(Throwable throwable);        void onSuccess(BaseObjectBean bean);

 MainPresenter 的完整代码:

public class MainPresenter extends BasePresenter implements MainContract.Presenter {    private MainContract.Model model;    public MainPresenter() {        model = new MainModel();    }    @Override    public void login(String username, String password) {        if (!isViewAttached()) {            return;        }        mView.showLoading();        model.login(username, password)                .compose(RxScheduler.>Flo_io_main())                .as(mView.>bindAutoDispose())                .subscribe(new Consumer>() {                    @Override                    public void accept(BaseObjectBean bean) throws Exception {                        mView.onSuccess(bean);                        mView.hideLoading();                    }                }, new Consumer() {                    @Override                    public void accept(Throwable throwable) throws Exception {                        mView.onError(throwable);                        mView.hideLoading();                    }                });    }}

MainPresenter 实现MainContract.Presenter 接口中的 login(String username, String password) 方法

实例化Model,在MainPresenter login(String username, String password)方法中,调用model的网络请求,将username、password放在model的login()方法中,进行请求服务器。
请求服务器前 使用MainContract.View中的 mView.showLoading()方法,进行显示加载中;在成功失败的回调中,使用对应的方法,以及取消加载。

其中BasePresenter、BaseView 是对Presenter以及View进行的封装

BaseView类:

public interface BaseView {    /**     * 显示加载中     */    void showLoading();    /**     * 隐藏加载     */    void hideLoading();    /**     * 数据获取失败     * @param throwable     */    void onError(Throwable throwable);    /**     * 绑定Android生命周期 防止RxJava内存泄漏     *     * @param      * @return     */     AutoDisposeConverter bindAutoDispose();}

 

至于为什么不把onSuccess()方法也封装,是因为请求网络,服务器返回的值是不一样的,在Contract > View接口中根据bean类设置onSuccess()

BasePresenter类:

public class BasePresenter {    protected V mView;    /**     * 绑定view,一般在初始化中调用该方法     *     * @param view view     */    public void attachView(V view) {        this.mView = view;    }    /**     * 解除绑定view,一般在onDestroy中调用     */    public void detachView() {        this.mView = null;    }    /**     * View是否绑定     *     * @return     */    public boolean isViewAttached() {        return mView != null;    }}

参考:https://www.jianshu.com/p/ae0b21d3238a 

更多相关文章

  1. android TextView的字体颜色设置的多种方法(续)
  2. Android 仿微信TabHost使用方法详解
  3. Android下拉列表使用方法
  4. Android获得屏幕分辨率的两种方法
  5. Android中getChildAt()方法介绍
  6. Android中NDK的使用方法
  7. Android中Parcelable接口用法
  8. Android的window类的常用方法
  9. Android 拨打webView 里面的电话号码的方法

随机推荐

  1. android通过图片名称获取资源识别码
  2. android中使用static、application、本地
  3. Android G711A编解码
  4. android银行卡操作步骤
  5. ANDROID音频系统散记之四:4.0音频系统HAL
  6. 常用adb命令
  7. Android - 详情页面【仿】淘宝App
  8. JS调用Android、Ios原生控件
  9. Android 自定义可拖拽,可放大缩小的ImageV
  10. Android里can't resolve symbol 问题