码迷,mamicode.com
首页 > 编程语言 > 详细

Retrofit结合RxJava个人使用经验

时间:2016-08-15 22:48:42      阅读:3979      评论:0      收藏:0      [点我收藏+]

标签:retrofit、rxjava

Retrofit出来也蛮久了,每次听其他小伙伴说起来都是那种吊吊的感觉,所以自己也赶紧加入其中,用完之后感觉真的很棒,当然学习的时候也是遇到不少问题,爽歪歪的感脚。具体该怎么用Retrofit,推荐鸿洋的文章 Retrofit2 完全解析 探索与okhttp之间的关系 ,写的比较清楚,我也不多花笔墨在这上面了,下面要说的是我个人使用Retrofit遇到的一些问题。

首先是引用库了,在module的build.gradle文件中添加

compile ‘io.reactivex:rxjava:1.1.6‘
compile ‘io.reactivex:rxandroid:1.2.1‘
compile ‘com.squareup.retrofit2:retrofit:2.1.0‘
compile ‘com.squareup.retrofit2:converter-gson:2.0.2‘
compile ‘com.squareup.retrofit2:adapter-rxjava:2.0.1‘

前两个是RxJava需要用到的库,中间的是Retrofit2的库,最后两个是Retrofit增加对Gson转换以及Rxjava支持的库,还有一个拦截器的

compile ‘com.squareup.okhttp3:logging-interceptor:3.0.1‘ 

可以方便的打印出网络请求的各种请求头,返回数据等,十分方便,不过在编译的时候我遇到了问题,所以我直接拷贝了源码HttpLoggingInterceptor这个类的代码,修改了一下拿来使用。在这个拦截器中,我们可以为请求添加统一的header

@Override
public Response intercept(Chain chain) throws IOException {
   Level level =
this.level;

   Request request = chain.request();
   request = request.newBuilder().addHeader(
"header", "value").build();
   
if (level == Level.NONE) {
       
return chain.proceed(request);
   }
   ...
}

然后为OkhttpClient配置这个拦截器

HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(
HttpLoggingInterceptor.Level.BODY);
okHttpClient = new OkHttpClient.Builder()
       .addInterceptor(interceptor)
       .retryOnConnectionFailure(
true)
       .connectTimeout(
15, TimeUnit.SECONDS)
       .build();

我们在使用Retrofit进行post请求的时候可以这么写

public interface UserService {
   
@POST("getuser")
   Observable<BaseResult<User>> getUser(
@Body RequestBody request);
}

比较尴尬的是我这样写提交到服务端的时候,服务端老是获取不到我提交的数据,后来沟通交流之后发现,服务端从Header和Form中查找需要的数据,而我提交到服务器并不在这两部分里面

User user = new User();
user.
userCode = "0000000";
MediaType JSON = MediaType.parse("application/json");
RequestBody body = RequestBody.create(JSON ,new Gson().toJson(user));
retrofit.create(UserService.class).getUser(body);

我是这么提交的,然而并没有什么用,后来查看RequestBody的继承关系之后看到了FormBody之后,原来还有这么一个直接提交Form键值对的类,真是粗心大条啊,使用这个类构建body,ok,木有问题了,服务端妥妥的拿到了数据,我也能愉快的玩耍下去了。

对于上面post请求的写法,有时候仅仅需要一两个参数我们就没必要那么麻烦了,写法可以如下:

@POST("getuser")
@FormUrlEncoded
Observable<BaseResult<User>> getUser(@Field("userCode") String userCode);

需要注意的是记得加上@FormUrlEncoded,不然运行时会报错。在retrifit构造这个接口的实例时,首先会根据接口方法中的注解来创建不同的ServiceMethod,ServiceMethod再解析参数注解来构建不同的ParameterHandler,各种各样的ParameterHandler如图:

技术分享

之后Retrofit根据ServiceMethod实例构建出了一个OkhttpCall,OkhttpCall在发起请求的时候再调用ServiceMethod的toRequest()方法,构建出一个Request,之后就是okhttp的请求流程,在toRequest()方法中,ServiceMethod根据之前构建的ParameterHandler去apply()运行每一组注解值,在这个过程里我们看到到了Field在apply中其实就是往RequestBuilder请求构造器中的FormBody添加了表单值,同理的其他的ParameterHandler在apply的过程中也是根据各自的属性去构造完善这个Request,最后交给okhttp调用。


接下来是对服务端返回的数据进行统一的预处理,通常服务端会返回一个这样的结果

{

"success":true,

"errorCode":"OK"

"data":{...}

}

data可以是数组,也可以是object,看具体情况,这样子看来我们可以封装一下:

class BaseResult<T>{

boolean success;

String errorCode;

T data;

}

嗯嗯,这样看起来还不错呢,然后结合上我们的Rxjava,来看看我们现在的代码:

Retrofit retrofit = new Retrofit.Builder().build();//实例化随便写写,大家就略过吧
UserService userService = retrofit.create(UserService.
class);
FormBody.Builder builder =
new FormBody.Builder();
builder.add(
"userCode","00000");
FormBody body = builder.build();
Observable<BaseResult<User>> user = userService.getUser(body);
user.subscribe(
new Observer<BaseResult<User>>() {
   
@Override
   
public void onNext(BaseResult<User> userBaseResult) {
       
if(userBaseResult.success){
           
//...
       
}else{
           
//on error
       
}
   }
   
@Override
   
public void onCompleted() {
   }
   
@Override
   
public void onError(Throwable e) {
       
//on error
   
}
});

等等,看起来有点怪怪的,每次我们都需要判断一下请求的结果是否成功,这样是不是比较low,一次请求就多了一次判断,感觉身心都很累啊,,于是乎我找了找资源,有两篇文章有提到了对服务器结果进行统一的预处理,给出传送门:

RxJava 与 Retrofit 结合的最佳实践

Rx处理服务器请求、缓存的完美封装

最后我是这么封装的

public class BaseFunc<T> implements Func1<BaseResult<T>,Observable<T>>{
   
@Override
   
public Observable<T> call(final BaseResult<T> tBaseResult) {
       
if(tBaseResult.success){
           
return Observable.create(new Observable.OnSubscribe<T>() {
               
@Override
               
public void call(Subscriber<? super T> subscriber) {
                   
try {
                       subscriber.onNext(
tBaseResult.data);
                       subscriber.onCompleted();
                   }
catch (Exception e){
                       subscriber.onError(e);
                   }
               }
           });
       }
else{
           
return Observable.error(new ApiException(tBaseResult.errorCode));
       }
   }
}

具体调用方式:

Retrofit retrofit = new Retrofit.Builder().build();//实例化随便写写,大家就略过吧
UserService userService = retrofit.create(UserService.
class);
FormBody.Builder builder =
new FormBody.Builder();
builder.add(
"userCode","00000");
FormBody body = builder.build();
Observable<BaseResult<User>> user = userService.getUser(body);
user
.flatMap(new BaseFunc<User>()).subscribe(new Observer<User>() {
   
@Override
   
public void onNext(User user) {
       
   }
   
@Override
   
public void onError(Throwable e) {
       
//on error
   
}
   
@Override
   
public void onCompleted() {

   }
});

其实就是在返回的结果上面再加一个Rx操作符观察BaseResult的具体值,最后留给我们的就是我们只想要的结果。



好了,具体想说的就是这么多,为什么会写这篇文章主要是FormBody挖的坑(其实是自己对http了解的不够),还有就是对其他作者提出的封装方法进行实践,结果失败了。。。老尴尬,最后自己封装了一下(为啥失败原因还在找。。。)以后有想到了再来补充。有什么错误的话,也请指出,Thank you.



补充:刚才去看了一下Rx处理服务器请求、缓存的完美封装的demo,作者使用的compose操作符对BaseResult进行的转换的问题是没有问题的,他的写法是 --》  类名.<具体泛型类>handleResult(),而我一直是没有加上具体泛型类(从来没有遇到这样的的一个泛型方法,果然是我太年轻,

/(ㄒoㄒ)/~~),此外如果没有使用类名去调用的话,依然编译不通过,这因该是编译器把<>当成了大于小于符号了,由此导致的。

Retrofit结合RxJava个人使用经验

标签:retrofit、rxjava

原文地址:http://linwg.blog.51cto.com/9120692/1838425

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!