本博客转自郭霖公众号:http://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650236866&idx=1&sn=da666831f67303eeb7a57c1591204b43&scene=24&srcid=0910wJAKSLdsEFTBKwKfTNor#wechat_redirect

http://blog.csdn.net/qq_27778869/article/details/52121208


MVP

MVP 是基于 MVC 的改进,相信大家都是从 MVC 走过的,可能很多人还会在项目中使用 MVC,我们传统的 MVC xml布局 充当就是 视图层(View)业务层兼模型层 的一些业务处理需要在我们 Activity 或 Fragment 中进行处理然后更新视图层。由于xml定义好的布局,一旦加载之后,只能通过动态更新,那么视图层和Model就建立了联系,因此二者的耦合度就提高了,那么一旦修改了其中的一个就有可能对另一产生影响。

同时所有的操作在我们的 Controller 中进行处理,Controller 就会显得十分的臃肿,可读性就降低了,导致后期的项目维护成本提高了不少。很多时候你需要和团队一起开发项目,如果你的同事有一天在你请假或者想修改功能的时候发现一个Activity都有上千行甚至更多的时候,他开始慌了,他慌的时候如果还找到你的话,你可能也慌了。有了 MVP 之后,妈妈再也不用担心我会慌了!

MVP model层 依然不变,只不过之前充当 Controller Activity或者Fragment 就变身为了 View层,而业务逻辑的实现是在我们的 Presenter 中。简单介绍完了 MVP,光说不练,一点效果都没有的,下面我们来进行 MVP 的三部曲。

本次案例是在进入程序的时候访问服务器的指定接口来获取当前服务器中apk的版本号,通过对比和当前应用程序的版本号,如果有新版本弹出一个土司提示用户更新,功能就这么简单。

  • 视图层需要哪些更新UI的操作?可能大家会好奇我为什么会问这个,这里我留下一个悬念,待会给大家细讲。这个问题的答案是弹出一个土司提示用户更新。

  • 怎么进行更新UI前的操作?

  • 何时告知视图层进行UI更新?

结合上面的三个问题,我们根据需求设计代码:

1. 定义一个 MvpView 的接口:

 public Interface MvpView {
//提示更新
void showMessage(); }

2. 定义一个 Model 类:

 public class MvpModel{
/*从服务器获取的apk版本*/
private String newApkVersion;
//这里我就随便给出一个,正确与否我就不得而知 这里面需要注意的query是跟上请求的参数,通过GET方法来请求的 ,你可能这会问我,不是说不知道正不正确的吗,那还解释这么多?不好意思哈,我这里说明好是为了下面讲到Retrofit 做铺垫的
public static final String GET_NEW_VER_URL="http://192.168.1:8080/app/index/type?version=query";
public String getNewApkVersion() {
return newApkVersion;
} public void setNewApkVersion(String newApkVersion) {
this.newApkVersion = newApkVersion; }

3. 定义一个基类 BasePresenter(当然大家也可以不用这么做):

 public abstract class BasePresenter<T> {

     /*这个基类的Presenter 主要的作用就是将当前Presenter持有的view 在合适的时候给清除掉*/
public T mView ;
public void attach(T mView){ this.mView=mView; } public void dettach(){ mView=null; } }

4. 定义一个实际操作的 MvpPresenter

 public class MvpPresenter extends BasePresenter<MvpView> {
private MvpModel mMvpModel;
private Context mContext;
private RequestQueue mRequestQueue;
//这里重写当前的构造函数 因为我们需要获取程序的版本,因此需要一个上下文对象
public MvpPresenter (Context mContext) {
this.mContext = mContext;
//当前的Mvp模式的讲解我是采用Volley进行网络请求的所以 就封装了一个VolleyManager用于获取唯一的RequestQueue对象
mRequestQueue = VolleyManager.getInstance(mContext).getRequestQueue();
//对业务层初始化为后面获取的apk版本进行存放
mUpdateModel = new MvpModel();
}
//由于逻辑处理放到我们的Presenter中了,因此我们需要将在Activity的onResume 时候进行版本的检查
public void onResume(){ } }

5. 开始视图层的构建了,不过在之前我们先创建一个 BaseMvpActivity 用于统一化管理我们的 MVP模式 的Activity的构建:

 public abstract class BaseMvpActivity<V,T extends BasePresenter<V> > extends AppCompatActivity {

  /*定义一个Presenter 用于解绑持有的View
*
* 在onCreate进行初始化Presenter的操作
* 在onResume中进行绑定
* 在onDestroy 中进行解绑
*
* */
public T presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter=initPresenter(); } @Override
protected void onResume() {
super.onResume();
presenter.attach((V)this);
} @Override
protected void onDestroy() {
super.onDestroy();
presenter.dettach();
} /* 这里是适配为不同的View 装载不同Presenter*/
public abstract T initPresenter(); }

6. 正式写我们的应用Activity了(当前Activity的布局中仅有一个TextView):

 public class MvpActivity extends BaseMvpActivity<MvpView,MvpPresenter> implements MvpView{
@Bind(R.id.tvShow)
TextView tvMsg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.activity_update);
ButterKnife.bind(this);
}
@Override
protected void onResume() {
super.onResume();
presenter.onResume();
}
@Override
public MvpPresenter initPresenter() {
return new MvpPresenter (getApplicationContext());
}
@Override public void showMessage(){ tvMsg.setText("有新版本需更新!"); Toast.makeText(getApplicationContext(),"更新版本啦",Toast.LENGTH_LONG).show(); } }

7. 看到上面的 MvpActivity 是不是觉得代码很清爽,那还不是把业务处理的逻辑丢给了 Presenter了,好了我们来具体看看 MvpPresenter 怎么写:

 //在前面贴出的代码中添加
pulic void onResume(){ getVerFromServer(); }
private void getVerFromServer(){ JsonObjectRequest jsonRequest = new JsonObjectRequest(Request.Method.GET, MvpModel.GET_NEW_VERSION ,null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.e("请求版本返回结果为:",response.toString()); try {
mUpdateModel.setNewApkVersion(response.getJSONObject("data").getString("version"));
//如果从服务器获取的版本和当前的版本相同,就可提示用户了
if(mUpdateModel.getNewApkVersion.equals(getCurrentVer())){
//这里就是合适的更新UI时间,通过这里把更新的实际传递出去
mView.showMessage();
} catch (JSONException e) {
e.printStackTrace();
} }
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) { }
});
jsonRequest.setTag("getVer");
mRequestQueue.add(jsonRequest); }
private String getCurrentVer(){
String verName="";
try {
verName=mContext.getPackageManager().getPackageInfo(context.getPackageName(),0).versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
Log.e("apkVer",verName);
return verName; }

Retrofit简单介绍及使用

相信大家在开发过程中被这个字眼给冲击过不少次,具体 Retrofit 是什么这里我就不详细介绍了,我们只针对它的简单应用来讲解:

1. 首先需要创建一个接口如 RetrofitCall,因为 Retrofit 是通过注解的形式构建方法的,下面我们来写一下:

 public interface RetrofitCall{
// 我们把之前定义好的api接口 拿来 http://192.168.1:8080/app/index/type?version=query
//这里我先简单给大家介绍一下 Retrofit 请求网络的接口形式要满足RESTful 形式(有不了解的可自填坑) 不够构成一般是这样的[协议类型:][//主机地址加端口(或者域名)][具体目录][请求参数]
//所以这个接口的具体目录(path)为app/index/type 也就是下面这个GET注解中应该填入的
@GET("app/index/type")
Call<VersionBean> getVer(@Query(version) String ver);
//如果有读者不知道这个VersionBean怎么生成的可以查看我的博客有一篇讲Retrofit的 其实就是利用GSONFromat 来实现的 }

2. 注册网络访问(这里的代码是在 Presenter 实现的):

 Retrofit mRetrofit =new Retrofit.Builder()
//这里为主机加端口(或域名)
.baseUrl("http://192.168.1:8080/")
.clent(new OkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.build();

3. 创建自定义接口实例并执行异步网络请求:

 RetrofitCall call=mRetrofit.create(RetrofitCall.class);
//这里需要把请求的参数填入
Call<VersionBean> myCall=call.getVer("1");
//异步执行
maCall.enqueue(new Callback<VersionBean>(){
@Override
public void onResposne(Call<VersionBean>call,retrofit2.Response<VersionBean> response) { if(response.body().getData().getVersion().equals(getCurrentVe r())){ mView.showMessage();
}
}
@Override
public void onFailure(Call<VersionBean> call, Throwable t) {
Log.e("callerro+"------------>"+t);
} });

通过RxJava改进Retrofit

RxJava 是一个异步操作的库,主要采用的观察者模式,在这里我只是简单的介绍,需要详细了解可以参考抛物线这篇:

给Android开发工程师的一篇关于RxJava的详解(这个已经推荐好几次了,值得一看呐)

http://gank.io/post/560e15be2dca930e00da1083

在这里我就不作过多介绍了,我们来演示 Retrofit 依靠 RxJava 来改进上面的代码,我们在 RetrofitCall 中添加一个新的注解:

 @GET("app/index/type")
Observable<VersionBean> getVerByRxJavaWithRetrofit(@Query("version") String ver);

接着在 Presenter 中填入如下的方法:

 private void requestDataByRxJavaWithRetrofit(){
Retrofit mRxjavaRetrofit= new Retrofit.Builder()
.baseUrl("http://192.168.1:8080/")
//由于需要转为Observable 需要添加RxJavaCallAdapterFactory
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitCall call= mRxjavaRetrofit.create(RetrofitCall.class);
call.getVerByRxJavaWithRetrofit(""1)
//指定时间消费在主线程
.observeOn(AndroidSchedulers.mainThread())
//事件产生在新线程
.subscribeOn(Schedulers.newThread())
//指定一个观察者
.subscribe(new Observer<Version>(){
@Override
public void onCompleted() { mView.showMessage();
} @Override
public void onError(Throwable e) { }
/*这个时候是订阅者需要跟新UI的时间了通知它更新*/
@Override
public void onNext(LogoBean logoBean) {
/*这里先不做判断*/ } } ); }

总结

上面对这三者的结合使用有了一个直观的介绍,其实 MVP模式 可以理解为更新UI需要什么操作,什么时候开始更新UI,怎么更新UI;而我们的 MVP模式 就是把这三种状态巧妙地分开,因此会让思路显得很清晰。

RxJava 正式基于这种设计,被观察者通过被订阅的形式在自己有新动态的时候告知观察者我改变了,剩下的就交给观察者做自己应该做的事情了!这样的设计模式很符合我们需求,也很利于团队开发,换个模式你会觉得效率大大提高,让我们一起加入 MVP+RxJava+Retrofit 的队列之中吧!

设计模式笔记之四:MVP+Retrofit+RxJava组合使用的更多相关文章

  1. Android MVP+Retrofit+RxJava实践小结

    关于MVP.Retrofit.RxJava,之前已经分别做了分享,如果您还没有阅读过,可以猛戳: 1.Android MVP 实例 2.Android Retrofit 2.0使用 3.RxJava ...

  2. 82.Android之MVP+Retrofit+RxJava实践小结

    转载:http://wuxiaolong.me/2016/06/12/mvpRetrofitRxjava/ 关于MVP.Retrofit.RxJava,之前已经分别做了分享,如果您还没有阅读过,可以猛 ...

  3. mvp+retrofit+rxjava

    引用 "retrofit" : "com.squareup.retrofit2:retrofit:2.0.1", "retrofit-adapter& ...

  4. Android okHttp网络请求之Retrofit+Okhttp+RxJava组合

    前言: 通过上面的学习,我们不难发现单纯使用okHttp来作为网络库还是多多少少有那么一点点不太方便,而且还需自己来管理接口,对于接口的使用的是哪种请求方式也不能一目了然,出于这个目的接下来学习一下R ...

  5. Android MVP开发模式及Retrofit + RxJava封装

    代码已上传到Github,因为接口都是模拟无法进行测试,明白大概的逻辑就行了! 欢迎浏览我的博客--https://pushy.site 1. MVP模式 1.1 介绍 如果熟悉MVP模式架构的话,对 ...

  6. 带你封装自己的MVP+Retrofit+RxJava2框架(一)

    前言 文本已经收录到我的Github个人博客,欢迎大佬们光临寒舍:我的GIthub博客 看完本篇文章的,可以看下带你封装自己的MVP+Retrofit+RxJava2框架(二),里面封装得到了改进 本 ...

  7. 基于Retrofit+RxJava的Android分层网络请求框架

    目前已经有不少Android客户端在使用Retrofit+RxJava实现网络请求了,相比于xUtils,Volley等网络访问框架,其具有网络访问效率高(基于OkHttp).内存占用少.代码量小以及 ...

  8. kotlin for android----------MVP模式下(OKHttp和 Retrofit+RxJava)网络请求的两种实现方式

    今天要说的干货是:以Kotlin,在MVP模式下(OKHttp和 Retrofit+RxJava)网络请求两种实现方式的一个小案例,希望对大家有所帮助,效果图: Retrofit是Square公司开发 ...

  9. 我们为什么要把Dagger2,MVP以及Rxjava引入项目中?

    1Why? 我们为什么要把Dagger2,MVP以及Rxjava引入项目中? 毫无疑问在Android开发圈中这三个技术是经常被提及的,如此多的文章和开源项目在介绍他们,使用他们,开发者也或多或少的被 ...

随机推荐

  1. HDU/5499/模拟

    题目链接 模拟题,直接看代码. £:分数的计算方法,要用double; #include <set> #include <map> #include <cmath> ...

  2. FRP 浅析

    一.Reactive? 请先看一个非常简单的小应用,它允许用户在一个搜索输入框里输入关键词,然后在其下方的结果区域实时显示从Flicker网站搜索得到的图片,当用户输入的关键词发生变化,显示的图片也会 ...

  3. 关于前台主键输入错误对后台hibernate方法的影响

    由于前台输入时开始不小心打错了主键为value=“${conf_id}”/ 导致后台得到的主键不是数字“1”而是“1/”所以到后台就算是进的updata方法结果运行的却是添加方法 原因可能是传入的对象 ...

  4. Jmeter的优点是什么?除了轻量级,它和LoadRunner有什么本质区别

    1.jmeter的架构和loadrunner原理一样,都是通过中间代理,监控和收集并发客户端发出的指令,把他们生成脚本,再发送到应用服务器,再监控服务器反馈结果的一个过程: 2.分布式中间代理功能在j ...

  5. stray '/241' in program 错误

    意思是c/c++中的编译错误. 该错误是指源程序中有非法字符,需要去掉非法字符.一般是由于从别的地方粘贴过来造成的. 方法:1.把所粘的文字放到记事本里就行了 2.把出错行的空格删掉重新打一下试试.

  6. scala模式匹配与样例类

    样本类:添加了case的类便是样本类.这种修饰符可以让Scala编译器自动为这个类添加一些语法上的便捷设定.如下: 1.添加与类名一致的工厂方法.也就是说,可以写成Var("x") ...

  7. Android Studio开发环境的配置

    为了使开发人员与时俱进, 在这里给大家讲解一下Android Studio的安装步骤及设置. 使用的是Android的最新版本,0.4.2版本,Android Studio可以脱离Eclipse单独运 ...

  8. discuz!迁移指南

    转自:http://jingyan.baidu.com/article/f7ff0bfc77114b2e26bb1390.html 曾经在本地搭建过一个discuz!论坛,现在买了域名和服务器,那么怎 ...

  9. Html基础详解之(CSS)

    css选择器 CSS选择器用于选择你想要的元素的样式的模式. “CSS”列表示在CSS版本的属性定义(CSS1,CSS2,CSS3). CSS id和class选择器 <!DOCTYPE htm ...

  10. C#中String和stringBuilder的区别

    Stringbuilder类是直接用于字符串操作的类,打个比方把(1)string aa="123456";(2)aa+="789"; (3)StringBui ...