本博客转自郭霖公众号:http://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650236866&idx=1&sn=da666831f67303eeb7a57c1591204b43&scene=24&srcid=0910wJAKSLdsEFTBKwKfTNor#wechat_redirectjava
http://blog.csdn.net/qq_27778869/article/details/52121208json
MVP 是基于 MVC 的改进,相信你们都是从 MVC 走过的,可能不少人还会在项目中使用 MVC,咱们传统的 MVC 中 xml布局 充当就是 视图层(View) ,业务层兼模型层 的一些业务处理须要在咱们 Activity 或 Fragment 中进行处理而后更新视图层。因为xml定义好的布局,一旦加载以后,只能经过动态更新,那么视图层和Model就创建了联系,所以两者的耦合度就提升了,那么一旦修改了其中的一个就有可能对另外一产生影响。设计模式
同时全部的操做在咱们的 Controller 中进行处理,Controller 就会显得十分的臃肿,可读性就下降了,致使后期的项目维护成本提升了很多。不少时候你须要和团队一块儿开发项目,若是你的同事有一天在你请假或者想修改功能的时候发现一个Activity都有上千行甚至更多的时候,他开始慌了,他慌的时候若是还找到你的话,你可能也慌了。有了 MVP 以后,妈妈不再用担忧我会慌了!api
在 MVP 中 model层 依然不变,只不过以前充当 Controller 的 Activity或者Fragment 就变身为了 View层,而业务逻辑的实现是在咱们的 Presenter 中。简单介绍完了 MVP,光说不练,一点效果都没有的,下面咱们来进行 MVP 的三部曲。服务器
本次案例是在进入程序的时候访问服务器的指定接口来获取当前服务器中apk的版本号,经过对比和当前应用程序的版本号,若是有新版本弹出一个土司提示用户更新,功能就这么简单。网络
视图层须要哪些更新UI的操做?可能你们会好奇我为何会问这个,这里我留下一个悬念,待会给你们细讲。这个问题的答案是弹出一个土司提示用户更新。app
怎么进行更新UI前的操做?异步
什么时候告知视图层进行UI更新?ide
结合上面的三个问题,咱们根据需求设计代码:函数
1. 定义一个 MvpView 的接口:
1 public Interface MvpView { 2 //提示更新 3 void showMessage(); 4 5 }
2. 定义一个 Model 类:
1 public class MvpModel{ 2 /*从服务器获取的apk版本*/ 3 private String newApkVersion; 4 //这里我就随便给出一个,正确与否我就不得而知 这里面须要注意的query是跟上请求的参数,经过GET方法来请求的 ,你可能这会问我,不是说不知道正不正确的吗,那还解释这么多?很差意思哈,我这里说明好是为了下面讲到Retrofit 作铺垫的 5 public static final String GET_NEW_VER_URL="http://192.168.1:8080/app/index/type?version=query"; 6 public String getNewApkVersion() { 7 return newApkVersion; 8 } 9 10 public void setNewApkVersion(String newApkVersion) { 11 this.newApkVersion = newApkVersion; 12 13 }
3. 定义一个基类 BasePresenter(固然你们也能够不用这么作):
1 public abstract class BasePresenter<T> { 2 3 /*这个基类的Presenter 主要的做用就是将当前Presenter持有的view 在合适的时候给清除掉*/ 4 public T mView ; 5 public void attach(T mView){ 6 7 this.mView=mView; 8 9 10 } 11 12 13 public void dettach(){ 14 15 mView=null; 16 17 } 18 19 }
4. 定义一个实际操做的 MvpPresenter:
1 public class MvpPresenter extends BasePresenter<MvpView> { 2 private MvpModel mMvpModel; 3 private Context mContext; 4 private RequestQueue mRequestQueue; 5 //这里重写当前的构造函数 由于咱们须要获取程序的版本,所以须要一个上下文对象 6 public MvpPresenter (Context mContext) { 7 this.mContext = mContext; 8 //当前的Mvp模式的讲解我是采用Volley进行网络请求的因此 就封装了一个VolleyManager用于获取惟一的RequestQueue对象 9 mRequestQueue = VolleyManager.getInstance(mContext).getRequestQueue(); 10 //对业务层初始化为后面获取的apk版本进行存放 11 mUpdateModel = new MvpModel(); 12 } 13 //因为逻辑处理放到咱们的Presenter中了,所以咱们须要将在Activity的onResume 时候进行版本的检查 14 public void onResume(){ 15 16 17 } 18 19 }
5. 开始视图层的构建了,不过在以前咱们先建立一个 BaseMvpActivity 用于统一化管理咱们的 MVP模式 的Activity的构建:
1 public abstract class BaseMvpActivity<V,T extends BasePresenter<V> > extends AppCompatActivity { 2 3 4 5 /*定义一个Presenter 用于解绑持有的View 6 * 7 * 在onCreate进行初始化Presenter的操做 8 * 在onResume中进行绑定 9 * 在onDestroy 中进行解绑 10 * 11 * */ 12 public T presenter; 13 @Override 14 protected void onCreate(Bundle savedInstanceState) { 15 super.onCreate(savedInstanceState); 16 presenter=initPresenter(); 17 18 } 19 20 @Override 21 protected void onResume() { 22 super.onResume(); 23 presenter.attach((V)this); 24 } 25 26 @Override 27 protected void onDestroy() { 28 super.onDestroy(); 29 presenter.dettach(); 30 } 31 32 /* 这里是适配为不一样的View 装载不一样Presenter*/ 33 public abstract T initPresenter(); 34 35 36 }
6. 正式写咱们的应用Activity了(当前Activity的布局中仅有一个TextView):
1 public class MvpActivity extends BaseMvpActivity<MvpView,MvpPresenter> implements MvpView{ 2 @Bind(R.id.tvShow) 3 TextView tvMsg; 4 @Override 5 protected void onCreate(Bundle savedInstanceState) { 6 super.onCreate(savedInstanceState); 7 8 setContentView(R.layout.activity_update); 9 ButterKnife.bind(this); 10 } 11 @Override 12 protected void onResume() { 13 super.onResume(); 14 presenter.onResume(); 15 } 16 @Override 17 public MvpPresenter initPresenter() { 18 return new MvpPresenter (getApplicationContext()); 19 } 20 @Override 21 22 public void showMessage(){ 23 24 tvMsg.setText("有新版本需更新!"); 25 26 Toast.makeText(getApplicationContext(),"更新版本啦",Toast.LENGTH_LONG).show(); 27 28 29 } 30 31 32 33 34 35 36 37 38 }
7. 看到上面的 MvpActivity 是否是以为代码很清爽,那还不是把业务处理的逻辑丢给了 Presenter了,好了咱们来具体看看 MvpPresenter 怎么写:
1 //在前面贴出的代码中添加 2 pulic void onResume(){ 3 4 getVerFromServer(); 5 6 7 } 8 private void getVerFromServer(){ 9 10 JsonObjectRequest jsonRequest = new JsonObjectRequest(Request.Method.GET, MvpModel.GET_NEW_VERSION ,null, new Response.Listener<JSONObject>() { 11 @Override 12 public void onResponse(JSONObject response) { 13 Log.e("请求版本返回结果为:",response.toString()); 14 15 try { 16 mUpdateModel.setNewApkVersion(response.getJSONObject("data").getString("version")); 17 //若是从服务器获取的版本和当前的版本相同,就可提示用户了 18 if(mUpdateModel.getNewApkVersion.equals(getCurrentVer())){ 19 //这里就是合适的更新UI时间,经过这里把更新的实际传递出去 20 mView.showMessage(); 21 } catch (JSONException e) { 22 e.printStackTrace(); 23 } 24 25 } 26 }, new Response.ErrorListener() { 27 @Override 28 public void onErrorResponse(VolleyError error) { 29 30 } 31 }); 32 jsonRequest.setTag("getVer"); 33 mRequestQueue.add(jsonRequest); 34 35 36 } 37 private String getCurrentVer(){ 38 String verName=""; 39 try { 40 verName=mContext.getPackageManager().getPackageInfo(context.getPackageName(),0).versionName; 41 } catch (PackageManager.NameNotFoundException e) { 42 e.printStackTrace(); 43 } 44 Log.e("apkVer",verName); 45 return verName; 46 47 }
相信你们在开发过程当中被这个字眼给冲击过很多次,具体 Retrofit 是什么这里我就不详细介绍了,咱们只针对它的简单应用来说解:
1. 首先须要建立一个接口如 RetrofitCall,由于 Retrofit 是经过注解的形式构建方法的,下面咱们来写一下:
1 public interface RetrofitCall{ 2 // 咱们把以前定义好的api接口 拿来 http://192.168.1:8080/app/index/type?version=query 3 //这里我先简单给你们介绍一下 Retrofit 请求网络的接口形式要知足RESTful 形式(有不了解的可自填坑) 不够构成通常是这样的[协议类型:][//主机地址加端口(或者域名)][具体目录][请求参数] 4 //因此这个接口的具体目录(path)为app/index/type 也就是下面这个GET注解中应该填入的 5 @GET("app/index/type") 6 Call<VersionBean> getVer(@Query(version) String ver); 7 //若是有读者不知道这个VersionBean怎么生成的能够查看个人博客有一篇讲Retrofit的 其实就是利用GSONFromat 来实现的 8 9 }
2. 注册网络访问(这里的代码是在 Presenter 实现的):
1 Retrofit mRetrofit =new Retrofit.Builder() 2 //这里为主机加端口(或域名) 3 .baseUrl("http://192.168.1:8080/") 4 .clent(new OkHttpClient()) 5 .addConverterFactory(GsonConverterFactory.create()) 6 .build();
3. 建立自定义接口实例并执行异步网络请求:
1 RetrofitCall call=mRetrofit.create(RetrofitCall.class); 2 //这里须要把请求的参数填入 3 Call<VersionBean> myCall=call.getVer("1"); 4 //异步执行 5 maCall.enqueue(new Callback<VersionBean>(){ 6 @Override 7 public void onResposne(Call<VersionBean>call,retrofit2.Response<VersionBean> response) { 8 9 10 if(response.body().getData().getVersion().equals(getCurrentVe r())){ 11 12 mView.showMessage(); 13 } 14 } 15 @Override 16 public void onFailure(Call<VersionBean> call, Throwable t) { 17 Log.e("callerro+"------------>"+t); 18 } 19 20 });
RxJava 是一个异步操做的库,主要采用的观察者模式,在这里我只是简单的介绍,须要详细了解能够参考抛物线这篇:
给Android开发工程师的一篇关于RxJava的详解(这个已经推荐好几回了,值得一看呐)
http://gank.io/post/560e15be2dca930e00da1083
在这里我就不做过多介绍了,咱们来演示 Retrofit 依靠 RxJava 来改进上面的代码,咱们在 RetrofitCall 中添加一个新的注解:
1 @GET("app/index/type") 2 Observable<VersionBean> getVerByRxJavaWithRetrofit(@Query("version") String ver);
接着在 Presenter 中填入以下的方法:
1 private void requestDataByRxJavaWithRetrofit(){ 2 Retrofit mRxjavaRetrofit= new Retrofit.Builder() 3 .baseUrl("http://192.168.1:8080/") 4 //因为须要转为Observable 须要添加RxJavaCallAdapterFactory 5 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 6 .addConverterFactory(GsonConverterFactory.create()) 7 .build(); 8 RetrofitCall call= mRxjavaRetrofit.create(RetrofitCall.class); 9 call.getVerByRxJavaWithRetrofit(""1) 10 //指定时间消费在主线程 11 .observeOn(AndroidSchedulers.mainThread()) 12 //事件产生在新线程 13 .subscribeOn(Schedulers.newThread()) 14 //指定一个观察者 15 .subscribe(new Observer<Version>(){ 16 @Override 17 public void onCompleted() { 18 19 mView.showMessage(); 20 } 21 22 @Override 23 public void onError(Throwable e) { 24 25 } 26 /*这个时候是订阅者须要跟新UI的时间了通知它更新*/ 27 @Override 28 public void onNext(LogoBean logoBean) { 29 /*这里先不作判断*/ 30 31 } 32 33 34 } ); 35 36 }
上面对这三者的结合使用有了一个直观的介绍,其实 MVP模式 能够理解为更新UI须要什么操做,何时开始更新UI,怎么更新UI;而咱们的 MVP模式 就是把这三种状态巧妙地分开,所以会让思路显得很清晰。
而 RxJava 正式基于这种设计,被观察者经过被订阅的形式在本身有新动态的时候告知观察者我改变了,剩下的就交给观察者作本身应该作的事情了!这样的设计模式很符合咱们需求,也很利于团队开发,换个模式你会以为效率大大提升,让咱们一块儿加入 MVP+RxJava+Retrofit 的队列之中吧!