闲来无事想起好久没看文章了,也没写什么东西,心血来潮将自己对MVP+RxJava+Retrofit框架的理解记录下来方便以后回看,
相信很多开发者都知道目前常用流行的开发网络框架,MVC,MVP,包括MVP变种的passive view,MVVM等,现在来结合代码来谈谈,首先我有必要说说MVC这个伴随自己一年的伙计,MVC的流程大概如下1、view接受用户请求。2、view传递请求给Controller。3、Controller操作model进行数据更新。4、model通知view变化,5、view显示数据。其实我们一般没这么复杂,都是一个对象类,然后不管什么都往activity里面放,所以传统的MVC很少去细化。下面着重说说MVP,MVP将请求和数据显示严格的区分开,不再什么都去activity中去操作了,请求我们就在M层中去操作,V层显示数据,P层作为两者的纽带来处理业务逻辑。
首先我们引入rxjava和retrofit远程仓库
compile "io.reactivex.rxjava2:rxjava:$rootProject.ext.rxjava2Version" compile "com.squareup.retrofit2:retrofit:$rootProject.ext.retrofit2Version" compile "com.squareup.retrofit2:converter-scalars:$rootProject.ext.retrofit2Version" compile "com.squareup.retrofit2:converter-gson:$rootProject.ext.retrofit2Version" compile "com.squareup.retrofit2:adapter-rxjava2:$rootProject.ext.retrofit2Version" compile "com.trello.rxlifecycle2:rxlifecycle:$rootProject.ext.rxlifecycle" //compile "com.trello.rxlifecycle2:rxlifecycle-android:$rootProject.ext.rxlifecycle" compile "com.trello.rxlifecycle2:rxlifecycle-components:$rootProject.ext.rxlifecycle" compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
其次我们要去初始化retrofit的,retrofit是基于OkHttp框架的封装。
public class RetrofitHelper { private static OkHttpClient client; static { initClient(); } public static IApiService getBook(){ return creatService(IApiService.class,IApiService.Host); } public static <T> T creatService(Class<T> clzz, String s) { Retrofit retrofit = new Retrofit.Builder() .baseUrl(s) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .client(client) .build(); return retrofit.create(clzz); } private static void initClient(){ HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(String message) { try { String text = URLEncoder.encode(message,"utf-8"); LoggUtils.e("http",text); }catch (Exception e){ e.printStackTrace(); LoggUtils.e("http",e.getMessage()); } } }); interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); class NetIntercepter implements Interceptor{ @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); if (request.method().equals("POST")) { if (request.body() instanceof FormBody) { request = addPostFormParams(request); } else if (request.body() instanceof MultipartBody) { request = addPostMultiParams(request); } } else if (request.method().equals("GET")) { request = addGetParams(chain); } return chain.proceed(request); } } client= new OkHttpClient.Builder() .addInterceptor(interceptor) .connectTimeout(IApiService.TIMEOUT, TimeUnit.MILLISECONDS) .addNetworkInterceptor(new NetIntercepter()) .build(); } private static Request addPostMultiParams(Request request) { MultipartBody.Builder builder = new MultipartBody.Builder().addFormDataPart("deviceId","123456"); MultipartBody body = (MultipartBody) request.body(); for (int i = 0;i<body.size();i++){ builder.addPart(body.part(i)); } body = builder.build(); request = request.newBuilder().post(body).build(); return request; } /** * get请求数据提交的方法 * @param chain * @return */ private static Request addGetParams(Interceptor.Chain chain) { Request request = chain.request(); HttpUrl urlBuilder = request.url() .newBuilder() .addQueryParameter("deviceId", "123456").build(); request = request.newBuilder() .url(urlBuilder) .build(); return request; } /** * post 请求提交数据的方法 * @param request * @return */ private static Request addPostFormParams(Request request) { FormBody.Builder builder = new FormBody.Builder(); FormBody body = (FormBody) request.body(); for (int i = 0;i<body.size();i++){ builder.addEncoded(body.encodedName(i),body.encodedValue(i)); } body = builder.addEncoded("deviceId","123456").build(); request = request.newBuilder().post(body).build(); return request; } }
剩下的我们来建一个服务接口,IApiService,
public interface IApiService { long TIMEOUT = 15000; String Host = "https://api.xxxx.com/";//这是服务器地址 // String Srevice_Url = Host+"api/random/"; @GET("xxxxx")//这是接口地址 Observable<BaseBean<List<Book>>> searchBook(@Query("q") String bookName); }
所有的接口全部在在这里进行全面管理。
当然我们还需要一个最重要的点就是,我们网络请求的方法。
public abstract class DefaultObservable<T> implements Observer<BaseBean<T>> { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(BaseBean<T> tBaseBean) { if (tBaseBean.getCount()>0){ sucess(tBaseBean.getBooks()); }else { onFail("服务异常"); } } @Override public void onError(Throwable e) { if (e instanceof ParseException || e instanceof JSONException || e instanceof ParseException){ ToastUtils.show("解析错误"); }else if ( e instanceof HttpException){ ToastUtils.show("网络错误"); }else if (e instanceof ConnectException){ ToastUtils.show("连接错误"); }else if (e instanceof InterruptedException){ ToastUtils.show("连接超时"); }else { ToastUtils.show("未知错误"); } } @Override public void onComplete() { } public abstract void sucess(T t); public abstract void showError(String msg); public void onFail(String t){ if (TextUtils.isEmpty(t)) { ToastUtils.show(t); } else { ToastUtils.show(t); } } }这个类是Retrofit中重要的东西,这个是接收推送通知的一个接口,说白了,就是对请求做出回应,类似httpclient中的response。
MVP很重要的一个点就是,我们必须和服务端约定返回数据的格式,
public class BaseBean <T> { public int code;
public String message;
public T t;//t代表的是我们各个数据模型的泛型。}
我们建一个baseBean来存放约定的数据格式,比如我需要一个student类,那么我就用student类来继承basebean。
至此,前戏网络框架结构已经完成,接下来我们针对MVP来说说。
1、M层 会有一个BaseModel接口,里面方法自定定义这个接口主要用来定义Model层的共有方法。
其次会有一个对应类MyMOdel(代表不同的业务model)请求数据,
public class SearchModel implements BaseModel{ public DefaultObservable<List<Book> >getData(final MyCallBack<Book> callBack) { return new DefaultObservable<List<Book>>() { @Override public void sucess(List<Book> bean) { for (Book book : bean) { callBack.loadSucess(book); } } @Override public void showError(String mag) { callBack.loadError(mag); } }; } }
P 层 因为P层是M 和 V 的纽带,所以这里有一个BasePresenter来连接M V,并初始化 M V;
public class BasePresenter<V extends BaseView,M extends BaseModel> { public V mView; public M mModel; public void setPresenter(V view,M model){ this.mView = view; this.mModel = model; } public void setPresenter(V view){ this.mView = view; } }
其次对应的还有各个presenter,
public class SearchPresenter extends BasePresenter<SearchView, SearchModel>{ public void searchBook(String name){ RetrofitHelper.getBook().searchBook(name) .subscribeOn(Schedulers.io())//运行在子线程,表示读取 .observeOn(AndroidSchedulers.mainThread())//运行在主线程 .subscribe(mModel.getData(new MyCallBack<Book>() { @Override public void loadSucess(Book book) { mView.searchSusses(book); } @Override public void loadError(String t) { mView.searchFail(t); } })); } }我们看到,P实际的作用就是通过model来获取数据,然后将数据交个V层显示。
V 层 同理需要有一个BaseView接口来定义所有V层共有的方法
public interface BaseView {
LifecycleTransformer bindLifecycle();
}
记住,我们需要在
BaseView 中来使用第三方的rxlifecycle,他可以让Observable发布的事件和当前的组件绑定,实现生命周期同步。从而实现当前组件生命周期结束时,自动取消对Observable订阅。
对应的View
public interface SearchView extends BaseView{ void searchSusses(Book book);//数据返回成功要做的事 void searchFail(String errorMsg);
}
得到数据后要做的逻辑。
但是 , 但是 ,但是 重要事情说三遍,Google Assistant官方确不建议这样写,这样写的逻辑上没错,但会是开发流程更加复杂,
接口多余,毫无意义的代码变多,如果我们修改了对应presenter中逻辑,那么我们还需要修改presenter接口中的逻辑;很不方便,官方建议写
一个契约类来实现管理,一眼可以看到,所有的方法统一由契约类来管理,所以修改如下;
public interface BookContract {
interface View extends BaseView<Presenter> {
void Susses(Book book);//数据返回成功要做的事 void Fail(String errorMsg);}
abstract Presenter extends BasePresenter<View,Model>{
public void abstract getBook();
}
}
可以看到,契约类将P和V都统一起来管理。这样我们可以简化开发流程,更加明确了MVP各个层的工作解耦。
推荐一下MVP官方实现的文章。点击打开链接