Retrofit2+RxJava的整合
Retrofit2
RxJava
lambda
近期看到很多关于RxJava的项目,一开始还不太明白,简单的说就是用观察者模式实现的异步操作,用于代替过去的AsyncTask和Handle。
早先在使用网络访问中一直使用的是 okhttp,后来发现 Retrofit2 像注解式,这两个同样属于square,然后就想用Retrofit2结合RxJava弄一个网络访问的请求,在RxJava中会用到java8的lambda,写法看起来挺溜的 ( ) -> { } 。 最近用的时候踩了不少坑,后面会有填坑的方法。
Retrofit2 ( okhttp + jackson + rxjava )
RxJava ( rxandroid extends rxjava)
初次使用
引入关联、lambda支持
/* build.gradle */
classpath 'me.tatarka:gradle-retrolambda:3.2.5'
/* app.gradle*/
apply plugin: 'me.tatarka.retrolambda'
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
//引入
dependencies {
compile 'com.squareup.retrofit2:retrofit:2.0.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'
compile 'com.squareup.retrofit2:converter-jackson:2.0.0'
compile 'io.reactivex:rxjava:1.1.2'
compile 'io.reactivex:rxandroid:1.1.0'
}
Retrofit基本配置
/**
* Retrofit基本配置
* Created by 剑指锁妖塔 on 2016/3/22.
*/
public class AHttp {
private static final String baseUrl = "http://fylder.me/photo/";
/**
* 获取一个ApiService
*
* @return ApiService
*/
public static <T> T getInstance(final Class<T> service) {
Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //RxJava回调
.addConverterFactory(new StringConverterFactory()) //解析String
.addConverterFactory(JacksonConverterFactory.create()) //jackson解析json
.baseUrl(baseUrl)
.build();
return retrofit.create(service);
}
}
定义请求接口
/**
* 定义数据请求api
* Created by 剑指锁妖塔 on 2016/3/22.
*/
public interface UserServerImpl {
@FormUrlEncoded
@POST("user/login_account")
Observable<LoginEntity> login(@Field("user") String user, @Field("pass") String pass);
}
网络请求
/**
* 网络请求
* Created by 剑指锁妖塔 on 2016/3/22.
*/
public class UserHttpRequest {
/**
* 返回一个Observable
*/
public static Observable<LoginEntity> login(String username, String password) {
UserServerImpl server = AHttp.getInstance(UserServerImpl.class);
Observable<LoginEntity> login = server.login(username, password);
return login.subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread());
}
}
执行
void post() {
UserHttpRequest.login("fylder", "123").subscribe(
s -> Logger.json(s.toString()),
throwable -> Logger.e(throwable.getMessage()));
}
subscribe(final Action1<? super T> onNext, final Action1
以下在开发时遇到的问题
Q1: @POST传参问题
get请求在使用@Query()
注入参数是没问题,但在post请求就莫名其妙提示服务器接收不到,得换@Field
配合@FormUrlEncoded
,原因是服务器需要表格提交,当然一般情况下不要求form-data的形式@Query()也是可行。
get方式
@GET("user/login_account")
Observable<LoginEntity> login(@Query("user") String user, @Query("pass") String pass);
post方式
@FormUrlEncoded
@POST("user/login_account")
Observable<LoginEntity> login(@Field("user") String user, @Field("pass") String pass);
Q2: Observable<String>
当需要返回String类型时,仅使用默认的json解析会出问题,这就要在Retrofit配置时加入一个过滤转换器,而且要放在json解析转换器之前,否则无效。
.addConverterFactory(new StringConverterFactory()) //解析String
/**
* String转换器
* Created by 剑指锁妖塔 on 2016/3/22.
*/
public class StringConverterFactory extends Converter.Factory {
private static final MediaType MEDIA_TYPE = MediaType.parse("text/plain");
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
if (String.class.equals(type)) {
return new Converter<ResponseBody, String>() {
@Override
public String convert(ResponseBody value) throws IOException {
return value.string();
}
};
}
return null;
}
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
if (String.class.equals(type)) {
return new Converter<String, RequestBody>() {
@Override
public RequestBody convert(String value) throws IOException {
return RequestBody.create(MEDIA_TYPE, value);
}
};
}
return null;
}
}