MVP

作者: Anwfly | 来源:发表于2019-04-07 23:11 被阅读41次

    1.前言

    • 你是否遇到过Activity/Fragment中成百上千行代码,完全无法维护,看着头疼?
    • 你是否遇到过因后台接口还未写而你不能先写代码逻辑的情况?
    • 你是否遇到过用MVC架构写的项目进行单元测试时的深深无奈?
    • 如果你现在还是用MVC架构模式在写项目,请先转到MVP模式!

    2.MVC架构

    ①MVC概述

    MVC架构模式最初生根于服务器端的Web开发,后来渐渐能够胜任客户端Web开发,再后来因Android项目由XML和Activity/Fragment组成,慢慢的Android开发者开始使用类似MVC的架构模式开发应用.

    • M层:模型层(model),主要是实体类,数据库,网络等存在的层面,model将新的数据发送到view层,用户得到数据响应.

    • V层:视图层(view),一般指XML为代表的视图界面.显示来源于model层的数据.用户的点击操作等事件从view层传递到controller层.

    • C层:控制层(controller),一般以Activity/Fragment为代表.C层主要是连接V层和M层的,C层收到V层发送过来的事件请求,从M层获取数据,展示给V层.


      mvc.jpg

    从上图可以看出M层和V层有连接关系,而Activity有时候既充当了控制层又充当了视图层,导致项目维护比较麻烦.

    ②MVC架构优缺点

    • A. 缺点

    M层和V层有连接关系,没有解耦,导致维护困难.
    Activity/Fragment中的代码过多,难以维护.
    Activity中有很多关于视图UI的显示代码,因此View视图和Activity控制器并不是完全分离的,当Activity类业务过多的时候,会变得难以管理和维护.尤其是当UI的状态数据,跟持久化的数据混杂在一起,变得极为混乱.

    • B. 优点

    控制层和View层都在Activity中进行操作,数据操作方便.
    模块职责划分明确.主要划分层M,V,C三个模块.

    3.MVP架构

    mvp.jpg

    ①概述

    MVP,即是Model,View,Presenter架构模式.看起来类似MVC,其实不然.从上图能看到Model层和View层没有相连接,完全解耦.

    ②分层

    • M层:模型层(Model),此层和MVC中的M层作用类似.主要是实体类,数据库,网络等存在的层面

    • V层:视图层(View),在MVC中V层只包含XML文件,而MVP中V层包含XML,Activity和Fragment三者.理论上V层不涉及任何逻辑,只负责界面的改变,尽量把逻辑处理放到M层.

    • P层:通知层(Presenter),P层的主要作用就是连接V层和M层,起到一个通知传递数据的作用.

    ③原理

    用户触碰界面触发事件,View层把事件通知Presenter层,Presenter层通知Model层处理这个事件,Model层处理后把结果发送到Presenter层,Presenter层再通知View层,最后View层做出改变.这是一整套流程.

    ④. MVP架构优缺点

    • A. 缺点

    MVP中接口过多.
    每一个功能,相比于MVC要多写好几个文件.
    如果某一个界面中需要请求多个服务器接口,这个界面文件中会实现很多的回调接口,导致代码繁杂.
    如果更改了数据源和请求中参数,会导致更多的代码修改.
    额外的代码复杂度及学习成本.

    • B. 优点

    模块职责划分明显,层次清晰,接口功能清晰.
    Model层和View层分离,解耦.修改View而不影响Model.
    功能复用度高,方便.一个Presenter可以复用于多个View,而不用更改Presenter的逻辑.
    有利于测试驱动开发,以前的Android开发是难以进行单元测试.
    如果后台接口还未写好,但已知返回数据类型的情况下,完全可以写出此接口完整的功能.

    四.MVP架构实战

    ①MVP简单案例

    用户点击按钮后,Presenter层通知Model层请求处理网络数据,处理后Model层把结果数据发送给Presenter层,Presenter层再通知View层,然后View层改变TextView显示的内容.

    ②布局:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:gravity="center"
        android:orientation="vertical"
        tools:context=".view.SingleInterfaceActivity">
    
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="点击" />
    
        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="100px"
            android:text="请点击上方按钮获取数据" />
    </LinearLayout>
    

    ③页面:

    public class SingleActivity extends AppCompatActivity {
    
        private Button button;
        private TextView textView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_single_interface);
            button = findViewById(R.id.button);
            textView = findViewById(R.id.textView);
    
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                }
            });
    
        }
    }
    

    ④Api:

    public interface MyServer {
    
        public String Url = "http://api.shujuzhihui.cn/api/news/";
    
        @GET("categories?")
        Observable<ReBean> getData(@Query("appKey") String appKey);
    }
    

    ⑤bean:

    public class ReBean {
        private String ERRORCODE;
        private List<String> RESULT;
    
        public String getERRORCODE() {
            return ERRORCODE;
        }
    
        public void setERRORCODE(String ERRORCODE) {
            this.ERRORCODE = ERRORCODE;
        }
    
        public List<String> getRESULT() {
            return RESULT;
        }
    
        public void setRESULT(List<String> RESULT) {
            this.RESULT = RESULT;
        }
    }
    

    ⑥Model:

    public interface MyModel {
    
        void getData(String appKey, CallBack<ReBean, String> callBack);
    }
    
    public class MyModelImpl implements MyModel {
    
        @Override
        public void getData(String appKey, final CallBack<ReBean, String> callBack) {
    
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(MyServer.Url)
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
    
            MyServer myServer = retrofit.create(MyServer.class);
    
            Observable<ReBean> data = myServer.getData(appKey);
    
            data.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Observer<ReBean>() {
                        @Override
                        public void onSubscribe(Disposable d) {
    
                        }
    
                        @Override
                        public void onNext(ReBean reBean) {
    
                            //成功
                            //txt.setText(reBean.getRESULT().toString());
                            if (reBean!=null){
                                if (reBean.getERRORCODE().equals("0")){
                                    callBack.onSuccess(reBean);
                                }else{
                                    callBack.onFail("失败");
                                }
                            }else{
                                callBack.onFail("出现错误");
                            }
                        }
    
                        @Override
                        public void onError(Throwable e) {
    
                            //失败
                            callBack.onFail("出现错误");
                        }
    
                        @Override
                        public void onComplete() {
    
                        }
                    });
        }
    
    }
    

    ⑥CallBack:

    public interface CallBack<K, V> {
        void onSuccess(K data);
    
        void onFail(V data);
    }
    

    ⑦Presenter:

    public interface MyPresenter {
    
        void getData(String appKey);
    }
    
    public class MyPresenterImpl implements  MyPresenter, CallBack<ReBean,String> {
    
        private MyModel myModel;
        private MyView myView;
    
        public MyPresenterImpl(MyModel myModel,MyView myView) {
            this.myModel = myModel;
            this.myView = myView;
        }
    
        @Override
        public void getData(String appKey) {
            if (myModel!=null){
                myModel.getData(appKey, this);
            }
        }
    
        @Override
        public void onSuccess(ReBean data) {
            //如果Model层请求数据成功,则此处应执行通知View层的代码   
            if(myView!=null){
                myView.onSuccess(data);
            }
        }
    
        @Override
        public void onFail(String data) {
            //如果Model层请求数据失败,则此处应执行通知View层的代码
            if(myView!=null){
                myView.onFail(data);
            }
        }
    
    }
    

    ⑧IView:

    public interface MyView<K,V> {
    
        void onSuccess(K data);
    
        void onFail(V data);
    }
    
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener, MyView<ReBean,String> {
    
        private Button btn;
        private TextView txt;
        private String appKey = "908ca46881994ffaa6ca20b31755b675";
        private MyPresenterImpl myPresenter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            myPresenter = new MyPresenterImpl(new MyModelImpl(), this);
    
            initView();
        }
    
        private void initView() {
            btn = (Button) findViewById(R.id.btn);
            txt = (TextView) findViewById(R.id.txt);
    
            btn.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn:
                    initData();
                    break;
            }
        }
    
        private void initData() {
            myPresenter.getData(appKey);
        }
    
        @Override
        public void onSuccess(ReBean data) {
            txt.setText(data.getRESULT().toString());
        }
    
        @Override
        public void onFail(String data) {
            txt.setText(data);
        }
    }

    相关文章

      网友评论

        本文标题:MVP

        本文链接:https://www.haomeiwen.com/subject/osdrvqtx.html