Retrofit+RxJava的使用
2016-09-26 17:32
309 查看
Retrofit+RxAndroid的使用
这一段时间,除了流行的React Native之外,还有不少流行的框架如
Retrofit,
Rx等等。
Retrofit简介:
在Android API4.4之后,Google官方使用了square公司推出的okHttp替换了HttpClient的请求方式。后来square公司又推出了基于okHttp的网络请求框架:Retrofit。Retrofit采用注解的方式进行配置相关信息,如地址,请求头,请求方式等等,另外又添加了Gson解析库的接口,接入流行的框架Rx,因为提供了配置基础设置的接口,因此存在良好的扩展性。
Retrofit的基础配置
Retrofit retrofit = new Retrofit.Builder() .baseUrl(url) // .addConverterFactory(FastJsonConverterFactory.create()) // .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .client(httpClient.addInterceptor(interceptor).addNetworkInterceptor(netInterceptor).build()) .build();
其中,
addConverterFactory方法是用来配置Gson解析库,
addCallAdapterFactory方法是用来添加Rx的适配器,通过
client可以来配置基础内容,如拦截器(配置统一的请求头,获取指定的相应头),缓存配置等等。
通过
retrofit.create(Class clazz)获取网络接口,
clazz为Interface类型,Interface中采用注解的方式去请求网络,方式如下:
GET请求方式:
@Headers("namev:alue") // @Headers({"key:value","key:value"}) @GET("URL") Call<ResponseBody> getConnection(@Query("param") String param);
GET请求方式(用来Encode):
@GET("URL") Call<ResponseBody> getConnection(@QueryMap(encode = true) Map<String, String> param);
POST请求方式(JSON请求体):
@POST("URL") Call<ResponseBody> getConnection(@Body("param") Object p1);
POST请求方式(键值对):
@POST("URL") Call<ResponseBody> getConnection(@FieldMap Map<String, String> params);
ResponseBody是未采用
ConverterFactory的
结果,因此需要通过API手动解析;而采用
ConverterFactory之后,则可以将
ResponseBody自动解析为指定的Object,eg:User:
@GET("URL") Call<User> getConnection(@Query("param") String param);
因此我们只需要建立java类:
public class HttpUtil{ publi Retrofit mRetrofit public HttpUtil(String baseUrl, Interceptor interceptor){ OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); mRetrofit = new Retrofit.Builder() .baseUrl(baseUrl) // .addConverterFactory(JsonConverterFactory.create()) .client(httpClient.addInterceptor(interceptor).builder()) .build(); } public <T> T getServer(Class<T> clazz){ return mRetrofit.create(clazz); } }
public interface UserServer{ @GET("URL") Call<ResponseBody> getConnection(@Query("param") String param); // @GET("URL") // Call<User> getConnection(@Query("param") String param); }
Retrofit的基础使用
使用步骤:通过配置
addConverterFactory,我们就能直接通过接口调用得到json解析的返回值,否则会返回Call,需要手动处理网络请求,通过
同步:call.execute().body().string(); 异步:call.enqueue(new Callback(){...});
获取网络响应:
ResponseBody response = new HttpUtil("http://baidu.com",new Interceptor(){ @Override public Response intercept(Chain chain) throws IOException { return chain.proceed(chain.request()); } }).create(UserServer.class).getConnection("param");
Rx简介
初步了解Rx
Rx是ReactiveX-响应式编程的简称,是一个函数库或者是开源框架。可以参考ReactiveX了解他的一些基本概念。接下来Rx的结合使用:
在Retrofit的简介中,我们提到有一个addCallAdapterFactory的基本配置,是用来做Rx的桥接器使用的。通过该设置,我们的Retrofit代码接口就可以华丽的变身为:
public interface UserServer{ @GET("URL") Observable<User> getConnection(@Query("param") String param); }
也就是说,我们顺利的建立了可观测对象(Observables),通过Observables提供的Api,可以对它进行类似于工厂的自动化生产一样的链式操作,大量的减轻了我们的代码编写工作和阅读维护工作。尤其在异步线程的处理和对原数据组合变化上,更是为我们提供了便利的处理机制。
小结:
关于Rx,更多的使用方式在官网上都有对应的API讲解,在这里就不再赘述了,我们只需要记住几个关键点:1. Observable:可观测对象 2. Operators: 操作符API的总称 3. Scheduler: 线程
Demo讲解
demo地址:RxRetrofitFrameWork思路详解:
Retrofit的核心还是okhttp,因此很我们对Retrofit的基本设置也其实操作到了okhttp。针对于不同的业务,网络请求大致有几点要求,总结如下:1. 常用的信息头,如:网络状态、系统类型以及版本、令牌...... 2. 缓存类型的设定:如服务器判别式缓存响应,无网络状态响应等等 3. 信息传输方式如Gzip的格式的特殊化处理 4. log日志的打印
如果还有更多的通用要求,欢迎留言。
因此针对以上几点,我们需要配置不同的拦截器去处理这件事情:
通过
addInterceptor添加的Interceptor主要是用于处理请求的,在
Response intercept(Chain chain)方法中,我们能够添加统一信息头;而通过
addNetworkInterceptor添加的Interceptor主要是用于处理由网络请求得到的非缓存结果的响应,也就是说,如果我们得到的是缓存响应,则不会经过由
addNetworkInterceptor添加的Interceptor处理,只会通过
addInterceptor添加的Interceptor处理。另外设置缓存目录和大小,设置响应失败的重试策略,也是根据业务需要去设定。因此,我们将这里的封装做为最底层的支持,提供网络请求器,生成请求句柄:
public class HttpManager { private Retrofit mRetrofit; private OkHttpClient mHttpClient; private NetServer mNetServer; public HttpManager(String url, Interceptor interceptor, Interceptor netInterceptor){ OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.cache(new Cache(new File(NetApplication.getInstance().getApplicationContext().getCacheDir(), "caches"), 1024 * 1024 * 100)); mHttpClient = builder.addInterceptor(interceptor).addNetworkInterceptor(netInterceptor).retryOnConnectionFailure(true).build(); mRetrofit = new Retrofit.Builder() .baseUrl(url) .client(mHttpClient) .build(); mNetServer = mRetrofit.create(NetServer.class); } public NetServer getServer(){ return mNetServer; } }
接下来是业务层的相关配置:
public class NetProxy { private HttpManager mManger; private String BASE_URL = ""; public NetProxy(){ mManger = new HttpManager(BASE_URL, new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request originalRequest = chain.request(); Request.Builder builder = originalRequest.newBuilder(); // HttpUrl originalHttpUrl = original.url(); // String queryString = originalHttpUrl.encodeQuery(); // 获取url中的参数部分 // String path = originalHttpUrl.url().getPath(); // 获取相对地址 // Buffer buffer = new Buffer(); // builder.body().writeTo(buffer); // String requestContent = buffer.readUtf8(); // 用于post请求获取form表单内容 builder.addHeader("key", "value"); builder.addHeader("Accept-Encoding", "gzip"); Request request = builder.build(); return chain.proceed(request); } }, new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response response = chain.proceed(request); Response.Builder builder = response.newBuilder(); if (response.header("Content-Encoding", "").contains("gzip")){ BufferedSource bufferedSource = Okio.buffer(new GzipSource(response.body().source())); String temStr = bufferedSource.readUtf8(); bufferedSource.close(); ResponseBody body = ResponseBody.create(MediaType.parse("application/json"), temStr); builder.body(body); }else{ BufferedSource bufferedSource = Okio.buffer(response.body().source()); String temStr =bufferedSource.readUtf8(); bufferedSource.close(); ResponseBody body = ResponseBody.create(MediaType.parse("application/json"), temStr); builder.body(body); } return builder.build(); } }); } public NetServer getNetServer(){ return mManger.getServer(); } }
一个商业级别的App通常是有着大量的接口Api的,因此当接口越多时,越难以维护。因此我们可以利用
FieldMap和
QueryMap进行封装处理,统一成一个请求接口,传递不同的参数值,因此我们的
NetServer如下:
public interface NetServer { @GET Call<ResponseBody> getRequest(@Url String url, @QueryMap Map<String, String> map); @FormUrlEncoded @POST Call<ResponseBody> postRequest(@Url String url, @QueryMap Map<String, String> queryMap, @FieldMap Map<String, String> postMap); }
这里没有文件的上传,欢迎提供代码进行补全。
每个Api都有着不同的请求参数长度,请求参数类型和请求地址,因此我们将这些内容整合为动态的参数对象,组成url,map的形式,方便我们接口类型的统一化管理。
现在我们的网络请求句柄创建好了,底层相应的配置也做好了,现在需要开启我们的请求过程。在这里注意,为什么没有选择RxAdapter和JSONConvertFactory,第一是因为如果使用了JSONConvertFactory,我们的返回类型则不是统一的
Call<ResponseBody>,而是指定的Bean;第二是因为很有可能,我们需要在IO线程处理一些信息,如果使用了RxAdapter则我们通过接口就直接创建了一个完整的Observable,不利于代码的添加。
创建监听器和协议:
public interface NetResultCallback<E> { void onStart(); void onSuccess(E data); void onFailed(int code, String msg); void cancel(); }
public class BaseServiceResult<T> { public int ret; public String msg; public T data; @Override public String toString() { return "BaseServiceResult{" + "ret=" + ret + ", msg='" + msg + '\'' + ", data=" + data + '}'; } }
public interface ErrorCode { int CODE_OK = 0; int CODE_TIME_OUT = -5000; int CODE_NET_ERROR = -5001; int CODE_RESPONSE_EMPTY = -5002; }
补全网络请求过程:
public void excute(final String mUrl, final Map<String, String> mQueryMap, final Map<String, String> mPostMap, final MethodType mMethodType, final Class mClazz){ Observable.create(new Observable.OnSubscribe<BaseServiceResult<T>>() { @Override public void call(Subscriber<? super BaseServiceResult<T>> subscriber) { Call<ResponseBody> responseBody = new NetProxy(). getNetServer().getRequest(mUrl, mQueryMap); // Call<ResponseBody> responseBody = new NetProxy().getNetServer().postRequest(mUrl, mPostMap, mQueryMap); try { String strJSON = responseBody.execute().body().string(); BaseServiceResult<T> baseServiceResult = JSON.<BaseServiceResult<T>>parseObject(strJSON, BaseServiceResult.class); if (baseServiceResult.data != null) { if (baseServiceResult.data instanceof JSONObject) { baseServiceResult.data = JSON.parseObject(((JSONObject) baseServiceResult.data).toJSONString(), mClazz); } else if (baseServiceResult.data instanceof JSONArray) { baseServiceResult.data = (T) JSON.parseArray(((JSONArray) baseServiceResult.data).toJSONString(), mClazz); } } subscriber.onNext(baseServiceResult); subscriber.onCompleted(); } catch (Exception e) { e.printStackTrace(); subscriber.onError(e); } } }).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(getSubscrobe()); }
private Subscriber<BaseServiceResult<T>> getSubscrobe(final NetResultCallback<T> mCallback){ Subscriber<BaseServiceResult<T>> mSubscriber = new Subscriber<BaseServiceResult<T>>() { @Override public void onStart() { super.onStart(); } @Override public void onCompleted() { } @Override public void onError(Throwable e) { if (mCallback != null) { mCallback.onFailed(ErrorCode.CODE_TIME_OUT, NetApplication.getInstance().getString(R.string.connect_time_out)); Log.e(TAG, "onError: " + e.getMessage()); } } @Override public void onNext(BaseServiceResult<T> tBaseServiceResult) { if (mCallback != null) { if (tBaseServiceResult == null){ mCallback.onFailed(ErrorCode.CODE_RESPONSE_EMPTY, NetApplication.getInstance().getString(R.string.connect_time_out)); return; } Log.i(TAG, "onNext: " + tBaseServiceResult.toString()); if (tBaseServiceResult.ret == ErrorCode.CODE_OK) { mCallback.onSuccess(tBaseServiceResult.data); }else{ mCallback.onFailed(tBaseServiceResult.ret, tBaseServiceResult.msg); } } } }; return mSubscriber;
现在基本流程已经跑通,网络部分的基础已经搭建好,然而这样的执行代码还是有着大量重复的感觉,因此我们需要对执行代码进行二次封装,由上面的方法来看,我们发现就相当于是一次下厨,准备好了原材料如:mUrl,mCallback,mClazz等等,就能够直接执行,因此我们将这些准备和执行视为一个整体,具备了基本属性和基本行为动作,顺便参照我们Rx的链式模式,我们封装如下:
public class NetProcessor<T> { private NetResultCallback<T> mCallback; private Map<String, String> mQueryMap; private Map<String, String> mPostMap; private String mUrl; private Class<T> mClazz; private @MethodType int mMethodType; private boolean mNeedRetry = true; private Subscriber<BaseServiceResult<T>> mSubscriber; private NetServer mServer; private static final String TAG = "NetProcessor"; public static <T> NetProcessor<T> get(){ NetProcessor<T> netProcessor = new NetProcessor<T>(); return netProcessor; } public static <T> NetProcessor<T> post(){ NetProcessor<T> netProcessor = new NetProcessor<T>(); netProcessor.mPostMap = new HashMap<String, String>(); return netProcessor; } private NetProcessor(){ mQueryMap = new HashMap<>(); mServer = Controller.getInstance().getmNetProxy().getNetServer(); } public NetProcessor<T> putParam(String key, String value) { mQueryMap.put(key, value); return this; } public NetProcessor<T> postParam(String key, String value){ if (mPostMap == null){ synchronized (this){ mPostMap = new HashMap<String, String>(); } } mPostMap.put(key, value); return this; } public NetProcessor<T> onQueryMap(Map<String, String> queryMap) { this.mQueryMap.putAll(queryMap); return this; } public NetProcessor<T> onPostMap(Map<String, String> postMap) { if (mPostMap == null){ mPostMap.putAll(postMap); } return this; } public NetProcessor<T> onUrl(String url) { this.mUrl = url; return this; } public NetProcessor<T> onCallback(NetResultCallback<T> callback) { this.mCallback = callback; return this; } public NetProcessor<T> onClazz(Class<T> clazz){ this.mClazz = clazz; return this; } public NetProcessor<T> onRetry(boolean needRetry){ this.mNeedRetry = needRetry; return this; } public NetProcessor<T> excute() { mCallback.onStart(); Observable.create(new Observable.OnSubscribe<BaseServiceResult<T>>() { @Override public void call(Subscriber<? super BaseServiceResult<T>> subscriber) { Call<ResponseBody> responseBody = null; switch (mMethodType){ case MethodType.METHOD_GET: responseBody = mServer.getRequest(mUrl, mQueryMap); break; case MethodType.METHOD_POST: responseBody = mServer.postRequest(mUrl, mPostMap, mQueryMap); break; } try { String strJSON = responseBody.execute().body().string(); BaseServiceResult<T> baseServiceResult = JSON.<BaseServiceResult<T>>parseObject(strJSON, BaseServiceResult.class); if (baseServiceResult.data != null) { if (baseServiceResult.data instanceof JSONObject) { baseServiceResult.data = JSON.parseObject(((JSONObject) baseServiceResult.data).toJSONString(), mClazz); } else if (baseServiceResult.data instanceof JSONArray) { baseServiceResult.data = (T) JSON.parseArray(((JSONArray) baseServiceResult.data).toJSONString(), mClazz); } } subscriber.onNext(baseServiceResult); subscriber.onCompleted(); } catch (Exception e) { e.printStackTrace(); subscriber.onError(e); } } }).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() { @Override public Observable<?> call(Observable<? extends Throwable> observable) { return observable.flatMap(new Func1<Throwable, Observable<?>>() { @Override public Observable<?> call(Throwable error) { if (mNeedRetry) { mNeedRetry = false; // For IOExceptions, we retry if (error instanceof IOException) { return Observable.just(null); } } // For anything else, don't retry return Observable.error(error); } }); } }) .subscribe(getSubscrobe()); return this; } public void cancel(){ if (mSubscriber != null && !mSubscriber.isUnsubscribed()){ mSubscriber.unsubscribe(); mCallback.cancel(); } } private Subscriber<BaseServiceResult<T>> getSubscrobe(){ mSubscriber = new Subscriber<BaseServiceResult<T>>() { @Override public void onStart() { super.onStart(); } @Override public void onCompleted() { } @Override public void onError(Throwable e) { if (mCallback != null) { mCallback.onFailed(ErrorCode.CODE_TIME_OUT, NetApplication.getInstance().getString(R.string.connect_time_out)); Log.e(TAG, "onError: " + e.getMessage()); } } @Override public void onNext(BaseServiceResult<T> tBaseServiceResult) { if (mCallback != null) { if (tBaseServiceResult == null){ mCallback.onFailed(ErrorCode.CODE_RESPONSE_EMPTY, NetApplication.getInstance().getString(R.string.connect_time_out)); return; } Log.i(TAG, "onNext: " + tBaseServiceResult.toString()); if (tBaseServiceResult.ret == ErrorCode.CODE_OK) { mCallback.onSuccess(tBaseServiceResult.data); }else{ mCallback.onFailed(tBaseServiceResult.ret, tBaseServiceResult.msg); } } } }; return mSubscriber; } @IntDef({MethodType.METHOD_GET, MethodType.METHOD_POST}) public @interface MethodType { // GET请求 int METHOD_GET = 0; // POST请求 int METHOD_POST = 1; } private String getQuertString(){ if (mQueryMap == null){ return ""; } List<QueryString> list = new ArrayList<>(); QueryString query = null; Set<String> set = mQueryMap.keySet(); StringBuilder queryBuilder = new StringBuilder(); for (String key : set) { query = new QueryString(key, mQueryMap.get(key)); list.add(query); } Collections.sort(list); int size = list.size(); try { for (int i = 0; i < size; i++) { queryBuilder.append(list.get(i).toStringAddAnd( i == 0 ? false : true)); } } catch (Exception e) { e.printStackTrace(); } return queryBuilder.toString(); } private String getPostString(){ if (mPostMap == null){ return ""; } Set<String> set = mPostMap.keySet(); StringBuilder postBuilder = new StringBuilder(); for (String key : set) { try { postBuilder.append("&").append(key).append("=").append(URLEncoder.encode(mPostMap.get(key), "UTF-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } postBuilder.deleteCharAt(0); return postBuilder.toString(); } }
应用如下:
public class UserBeanModel { public static NetProcessor getUser(NetResultCallback<UserBean> callback){ Map<String, String> params = new HashMap<>(); params.put("name", "username"); params.put("psw", "userpsw"); return NetProcessor.<UserBean>get() .onCallback(callback) .onRetry(true) .onClazz(UserBean.class) .onUrl("/get/user") .onQueryMap(params) .excute(); } }
最后通过
UserBeanModel.getUser(new NetResultCallback())执行就能得到相应的结果。
关于RxJava2和XML的结合,详见Retrofit接入RxJava2的使用以及XML在Retrofit中的使用。
相关文章推荐
- RxJava和Retrofit2.0的结合使用
- Retrofit 和 RxJava 结合使用
- Rxjava+Retrofit结合使用时的开发技巧
- [置顶] OKhttp、RXjava与retrofit的网络访问使用
- Android应用架构之Retrofit使用 RxJava 详解 jsoup Android 平滑图片加载和缓存库 Glide 使用详解
- 简单地使用下RxJava + Retrofit
- Retrofit2.0的学习以及Rxjava与Retrofit2的结合使用
- 在安卓上使用RxJava Retrofit OKHttp GSON
- Android中的Retrofit+OkHttp+RxJava缓存架构使用
- 进阶之路:MVP+Retrofit+RxJava组合使用
- Android 中 Retrofit 结合 RxJava使用
- Android中的RxJava,Retrofit,MVP的使用
- Android RxJava/RxAndroid结合Retrofit使用
- Square全家桶正传——Retrofit使用及配合RxJava实现最大效率开发
- Android-使用Mockito、Robolectric和RxJava及Retrofit进行单元测试
- 使用Retrofit和RxJava
- Retrofit2和RxJava配合使用Demo
- Retrofit2.0+RxJava+MVP+Bmob的使用
- Android 使用RxJava+Retrofit +Realm 组合加载数据 <读取缓存 显示 请求网络数据 缓存最新数据 更新界面>(一)
- Android应用架构之Retrofit和RxJava使用