美文网首页
这一定是最简单的MVP+Retrofit

这一定是最简单的MVP+Retrofit

作者: S蛋糕 | 来源:发表于2017-12-09 16:56 被阅读0次

    说明:不讲原理,不讲优化,就是干

    目标:学会如何搭建最最基本的mvp架构

    简介

    我承认画图不是我的强项

    MVP是MVC衍生出来的架构,现在也比较成熟了,用的人也多了,面试也会考了,所以你必须要知道了

    M:数据层(数据库,文件,网络等)

    V:UI层(Activity,Fragment,View及其子类,Adapter及其子类)

    P:中介(作用:关联V和M)

    经过思想斗争,我觉得理论上的东西解释再多不如代码敲一遍,下面用一个用户登陆功能讲解如何搭建MVP架构,顺便简单用下Retrofit网络请求库(别怕都有注释)总之,MVP记住一个核心思想:V层就只做UI的操作,所有的业务处理和数据处理都交给P层(不然要你何用)就相当于把Activity里你写的众多网络请求和数据处理代码统统提取封装到P里了

    MVP结构

    api:Retrofit专用的,就两行代码,和mvp无关,待会给你看

    bean:登陆的实体类,和mvp无关

    login:可以看出是按功能分包。他比平时见到的多出来两个类,一个是 LoginPresenter(P层),一个是 LoginContract(契约接口类,用于将P和V接口封装到一起)他们是mvp重要的组成部分

    架构图如下:

    思路

    mvp结构实现分三步:

    一,搞一个接口契约类Contract,内含V接口和P接口

    二,搞一个实现V接口的view类

    三,搞一个实现P接口的presenter类

    第一步:

    搞一个接口契约类Contract,内含V接口和P接口。V接口里面放的是UI更新方法(V接口的实现类用到的方法);P接口里面放的是网络请求,数据读取,文件读取等具体的业务操作方法(P接口的实现类用到的方法)

    从动态图可以看到,一共有三个地方有UI界面变化

    ①点击登陆展示等待加载遮罩

    ②登陆成功或者失败后取消等待加载遮罩

    ③取消等待加载遮罩的同时吐司

    所以V接口里会有三个UI更新方法,那么就在V接口写三个方法呗,值得注意的是setPresenter方法只是用来把V层和P层关联的,本身与UI更新无关,但是必须要有的

    P接口在本例中只需要实现一个登陆按钮触发的网络请求就可以啦,所以只有一个方法

    由此可见,契约类Contract把V和P接口封装在了一块,而V和P接口又把具体的view和presenter用到的方法封装在了一块

    /**

    * 包含View和Presenter的契约接口

    * Created by wangjiong on 2017/12/7.

    */

    publicinterfaceLoginContract{

    /**

    * 与UI相关,与view相关操作

    */

    interfaceView{

    // 定义Presenter

    voidsetPresenter();

    // 展示等待加载页面

    voidshowLoading();

    // 隐藏等待加载页面

    voidhideLoading();

    // 显示登陆信息

    voidshowLoginInfo(String msg);

    }

    /**

    * 与业务相关

    */

    interfacePresenter{

    /**

    * 登陆

    * @param userId      用户id

    * @param userPassword 密码

    */

    voidlogin(String userId, String userPassword);

    }

    }

    第二步:

    搞一个实现V接口的view类。本例中的view类就是LoginActivity。首先实现接口所有的方法是必须的,然后这里有两个地方需要注意

    一,我们是在实现V层接口setPresenter方法里通过LoginPresenter的构造方法将LoginActivity传递过去的(LoginPresenter是P的实现类),这里要记得主动调用一下setPresenter方法触发初始化presenter这个事

    二,就是所谓的MVP中V层和P层分隔开,UI和业务分隔开。比如本例登陆按钮的点击事件,他并不是我们平时看到的直接撸网络请求代码,而是调用了P层里的的方法,说人话就是把网络请求一大堆代码封装了一个方法放到了P层那个类里头了,我们在调用的时候传需要用到的参数就行了。你说坑不坑,这点玩意说的那么高大尚

    /**

    * MVP层中的View层

    */

    publicclassLoginActivityextendsAppCompatActivityimplementsLoginContract.View{

    privateLoginPresenter mPresenter;

    privateEditText mEtName, mEtPwd;

    privateLinearLayout mLayoutLoading;

    @Override

    protectedvoidonCreate(Bundle savedInstanceState){

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_login);

    setPresenter();// 初始化presenter(很重要!不能说重写就不管了,一定要在view初始化调用此方法)

    mEtName = findViewById(R.id.et_name);// 用户名

    mEtPwd = findViewById(R.id.et_pwd);// 密码

    mLayoutLoading = findViewById(R.id.layout_loading);// 遮罩层

    findViewById(R.id.btn_login).setOnClickListener(newView.OnClickListener() {// 登陆按钮

    @Override

    publicvoidonClick(View view){// 点击登陆不是直接请求网络,而是通过presenter请求网络,然后将请求回来的数据交给view来更新

    mPresenter.login(mEtName.getText().toString().trim(), mEtPwd.getText().toString().trim());

    }

    });

    }

    @Override

    publicvoidsetPresenter(){

    mPresenter =newLoginPresenter(this);// 一是为了实例化presenter,二是通过构造方法将view实例传递给presenter

    }

    @Override

    publicvoidshowLoading(){// 展示遮罩层

    mLayoutLoading.setVisibility(View.VISIBLE);

    }

    @Override

    publicvoidhideLoading(){// 隐藏遮罩层

    mLayoutLoading.setVisibility(View.GONE);

    }

    @Override

    publicvoidshowLoginInfo(String msg){// 吐司登陆信息

    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();

    }

    }

    第三步:

    搞一个实现P接口的presenter类。本例中presenter类就是LoginPresenter,可以看到他就一个构造方法(用来关联V层并获取view实例化对象)和一个请求网络数据的方法。高能预警:网络请求前UI页面需要展示一个遮罩层,所以调用了view的showLoading方法,请求结束后UI页面需要取消遮罩并吐司,所以调用了view的hideLoading方法和showLoginInfo方法

    /**

    * MVP中的P层

    * Created by wangjiong on 2017/12/7

    */

    publicclassLoginPresenterimplementsLoginContract.Presenter{

    privateLoginContract.View mView;

    publicLoginPresenter(LoginContract.View view){// 获取到view的实例化对象

    this.mView = view;

    }

    @Override

    publicvoidlogin(String userId, String password){

    mView.showLoading();// 调用view的展示遮罩方法(view用来更新具体的UI)

    // 网络请求(可以自己封装一个网络库)

    Retrofit retrofit =newRetrofit.Builder()

    .baseUrl("http://192.168.1.101:8080/merclienttest/")// 请求的url

    .addConverterFactory(GsonConverterFactory.create())// 设置Gson为实体类解析工具

    .build();

    LoginApi loginApi = retrofit.create(LoginApi.class);// 传入一个接口类并返回此类的实例对象

    Call call = loginApi.login(userId, password);// 调用类中定义的login方法

    call.enqueue(newCallback() {// retrofit异步请求

    @Override

    publicvoidonResponse(Call call, Response response){

    mView.hideLoading();// 调用view的隐藏遮罩方法(view用来更新具体的UI)

    mView.showLoginInfo(response.body().getMsg());// 调用view的吐司方法(view用来更新具体的UI)

    }

    @Override

    publicvoidonFailure(Call call, Throwable t){

    mView.hideLoading();

    }

    });

    }

    }

    全剧终

    妈个鸡这是啥玩意?完了?哈哈哈,没错这就是MVP。就是这么简单。只需要记住一个核心思想V层仅仅是处理UI页面的(只管化妆接客,拉皮条找老鸨子P),业务逻辑放在P层去处理(网络请求,数据库,文件等),P处理完之后再调用一下V层已经写好的对应更新UI的方法即可

    扩展

    没忘记Retrofit哦,简单介绍下使用方法

    分三步:

    一,搞一个接口类Api

    二,搞一个对应的实体类bean

    三,调用Retrofit方法请求网络

    第一步:搞一个Api接口。本例中是LoginApi

    第一行代码 @GET("login") 这个Get就代表get请求,如果换成Post那就代表post请求。login代表接口名(接口名需要后台提供)

    第二行代码 Call login(@Query("userId") String userId, @Query("password") String password); 其中 login 代表自己定义的一个方法,名字随便起(小驼峰式命名),@Query("userId") 代表接口中有个名为 userId 的参数, String userId 代表给这个参数传值,值为userId(名字随便起)

    /**

    * 登陆接口

    * Created by wangjiong on 2017/12/7.

    */

    publicinterfaceLoginApi{

    @GET("login")//get请求login接口(接口名需要后台提供)

    Calllogin(@Query("userId") String userId, @Query("password") String password);// 声明一个login的方法(随便写),两个string形参,并返回一个实体类LoginBean

    }

    没反应过来?

    jsonObject.put("userId",userId) 这样写懂了吧,第一个userId是接口里的参数名,第二个userId是你传的字符串值,名字随便搞的,叫啥都行

    你也可以@Query("userId") String myUserId这就等价于

    jsonObject.put("userId",myUserId  )  这里只是为了说明问题,所以不必太在意细节

    第二步,搞一个对应的实体类bean。这个对应本例中的LoginBean。推荐用GsonFormat插件自动生成,啥?没听过,你又不是妹子,百度吧

    publicclassLoginBean{

    /**

    * code : 200

    * msg : 登陆成功

    */

    privateString code;

    privateString msg;

    publicStringgetCode(){

    returncode;

    }

    publicvoidsetCode(String code){

    this.code = code;

    }

    publicStringgetMsg(){

    returnmsg;

    }

    publicvoidsetMsg(String msg){

    this.msg = msg;

    }

    }

    第三步,调用Retrofit方法请求网络。做完上面两步,就可以正常调用了,咋用?你又不是妹子,参考LoginPresenter吧

    /**

    * MVP中的P层

    * Created by wangjiong on 2017/12/7

    */

    publicclassLoginPresenterimplementsLoginContract.Presenter{

    privateLoginContract.View mView;

    publicLoginPresenter(LoginContract.View view){// 获取到view的实例化对象

    this.mView = view;

    }

    @Override

    publicvoidlogin(String userId, String password){

    mView.showLoading();// 调用view的展示遮罩方法(view用来更新具体的UI)

    // 网络请求(可以自己封装一个网络库)

    Retrofit retrofit =newRetrofit.Builder()

    .baseUrl("http://192.168.1.101:8080/merclienttest/")// 请求的url

    .addConverterFactory(GsonConverterFactory.create())// 设置Gson为实体类解析工具

    .build();

    LoginApi loginApi = retrofit.create(LoginApi.class);// 传入一个接口类并返回此类的实例对象

    Call call = loginApi.login(userId, password);// 调用类中定义的login方法

    call.enqueue(newCallback() {// retrofit异步请求

    @Override

    publicvoidonResponse(Call call, Response response){

    mView.hideLoading();// 调用view的隐藏遮罩方法(view用来更新具体的UI)

    mView.showLoginInfo(response.body().getMsg());// 调用view的吐司方法(view用来更新具体的UI)

    }

    @Override

    publicvoidonFailure(Call call, Throwable t){

    mView.hideLoading();

    }

    });

    }

    }

    源码地址:https://github.com/GodJiong/mvp

    相关文章

      网友评论

          本文标题:这一定是最简单的MVP+Retrofit

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