本文主要是介绍本人在项目中接入Rxjava2和Retrofit2的过程中的一些经验心得、遇到的问题,特别是本人的学习曲线,主要的概念介绍涉及较少,但是在文中会给出我在接入的过程中参考过的文章,希望能帮助大家快速的在项目中接入该框架,少走弯路。
之所以把Rxjava2放在前面是因为,我最开始的时候只想接入Rxjava2来体验高大上的响应式编程,但是在学习和接入Rxjava2的过程中,感觉到非常有必要将Retrofit也整合进来,Retrofit的API设计非常适合Rxjava,两者结合使用是最完美的,于是就在项目中同时引用了Rxjava2+Retroif2。从学习到最后完成接入大概耗时5天以上。在这个过程中,自己的编程思想得到了很大的锻炼和提高,从最后使用的结果来看,框架极大的简化了平时做网络请求的步骤,特别是做到了代码的解耦,极大的提高了代码的可阅读性。
在动手之前,建议大家先对MVP模式(http://www.cnblogs.com/changyiqiang/p/6044618.html)、
面向接口编程(http://blog.sina.com.cn/s/blog_6c969b4a0102vnh6.html)有一定认识,
对Retrofit2和Rxjava2(文中用RR代替)有一些基本的了解。
RxJava2.0教程(一)
http://www.jianshu.com/p/464fa025229e.
我所理解的RxJava——上手其实很简单
http://www.jianshu.com/p/5e93c9101dc5
Ok,所谓万事开头难,如果有想法的同学的一定要尽早开始。让我们从导包开始一步步搭建自己的RR框架:
compile 'io.reactivex.rxjava2:rxjava:2.0.6'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'com.squareup.retrofit2:retrofit:2.2.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
compile 'com.squareup.retrofit2:converter-gson:2.2.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.6.0'
public class PayMoneyEntity {
float money ;
public float getMoney() {
return money;
}
public void setMoney(float money) {
this.money = money;
}
}
这里推荐两个的插件:
使用GsonFormat可以根据JSON快速生成实体类
http://blog.csdn.net/dakaring/article/details/46300963
使用Android parcelable code generator可以快速得序列化对象
http://blog.csdn.net/kroclin/article/details/40902721
1、先写一个抽象类:
public abstract class BaseService {
protected abstract String getBaseUrl();
protected Retrofit baseRetrofit(){
OkHttpClient client=new OkHttpClient.Builder()
.addInterceptor(new AddPubicParamsInterceptor())//自定义的拦截器,用于添加公共参数
.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))//拦截器,用于日志的打印
.build();
Retrofit retrofit=new Retrofit.Builder()
.client(client)
.baseUrl(getBaseUrl())
.addConverterFactory(MyConvert.create())//对获得的结果进行解析和处理,是比较重要的部分,在我的项目中涉及到解密和一些业务逻辑判断
.addConverterFactory(GsonConverterFactory.create())//默认直接转化为实体类,不会进行解密等处理
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//Retrofit2与Rxjava2之间结合的适配器
.build();
return retrofit;
}
}
2、定义网络请求的接口:
public interface GetCustomListApi {
@GET("sample.client/pay/money")//这里是URL的后半段
Observable getPayInfo(@Query("user_id") String user_id);
}
3、管理Retrofit:
public class RestService extends BaseService {
private static final String BASE_REST_URL = "http://www.baidu.cn:80";//这里是URL的前半段
@Override
protected String getBaseUrl() {
return BASE_REST_URL;
}
public GetCustomListApi creatCustomApi(){
return baseRetrofit().create(GetCustomListApi.class);
}
}
1、首先我们来看一下Interceptor:
关于拦截器的介绍大家参考:
http://blog.csdn.net/oyangyujun/article/details/50039403
在我们的项目中大部分请求都需要添加公共参数,我们通过自定义的拦截器重写intercept方法即可:
public class AddPubicParamsInterceptor implements Interceptor {
@SuppressWarnings("deprecation")
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// 添加公共的新的参数
HttpUrl.Builder authorizedUrlBuilder = request.url()
.newBuilder();
Request.Builder build = request.newBuilder();
Map globalParams = new HashMap<>();//这里是我们的公共参数,根据自己项目实际情况获得,具体添加什么样的参数,在这里做逻辑判断即可
Iterator it = globalParams.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
//如果是中文/其他字符,会直接把字符串用BASE64加密,
String s = URLDecoder.decode(String.valueOf(entry.getValue()));
authorizedUrlBuilder.addQueryParameter((String) entry.getKey(), s);
}
//生成新的请求
Request newrequest = request.newBuilder()
.method(request.method(), request.body())
.url(authorizedUrlBuilder.build())
.build();
return chain.proceed(newrequest);
}
}
2、在定义网络请求接口大家参考:
Retrofit2.0 API使用解析
http://blog.csdn.net/zuck_t/article/details/50718774/
Android网络请求库 - Say hello to retrofit
http://blog.csdn.net/ghost_Programmer/article/details/52372065
这里当时我花费了比较多的时间,因为要找到适合自己项目的URL写法。
3、到了这一步我们终于把请求处理完了,最后让我们来看一下解析GsonConverterFactory——转换器,参考:
Retrofit 2.0 自定义Converter
http://blog.csdn.net/jdsjlzx/article/details/51860663
这里的解析处理也是耗了比较多的时间,来看代码:
public final class MyConvert extends Converter.Factory {
private final Gson gson;
public static MyConvert create(Gson gson) {
return new MyConvert(gson);
}
public static MyConvert create(){
return create(new Gson());
}
public MyConvert(Gson gson) {
this.gson = gson;
}
@Override
public Converter responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
TypeAdapter> adapter=gson.getAdapter(TypeToken.get(type));
return new DecodeResponseBodyConverter<>(gson,adapter);
}
@Override
public Converter, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter> adapter=gson.getAdapter(TypeToken.get(type));
return new RequestBodyConverter<>(gson, adapter);
}
}
public class DecodeResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final TypeAdapter adapter;
private final Gson gson;
DecodeResponseBodyConverter(Gson gson, TypeAdapter adapter) {
this.adapter = adapter;
this.gson = gson;
}
@Override
public T convert(ResponseBody responseBody) throws IOException {
String s = responseBody.string();
//s就是我们网络请求获得的字符串了,因为我们项目中以前的网络框架用到了把字符串封装为Response对象,为了保持一致和方便维护这里也继续使用Response对象。大家根据自己项目具体情况处理即可。
Response response = new Response(s);
//response.content是消息体,这里我们项目是进行解密处理,大家根据自己情况处理即可
String decodeBody = Utils.decode(response.content, true);
JsonReader jsonReader = gson.newJsonReader(new StringReader(decodeBody));
try {
return adapter.read(jsonReader);
} finally {
responseBody.close();
}
}
}
自定义的RequestBodyConverter跟GsonConverterFactory中用到的GsonRequestBodyConverter一样,就不贴代码了。
public class TestActivity extends Activity {
private GetCustomListApi customListApi = new RestService().creatCustomApi();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
customListApi.getPayInfo(UserDataUtils.getInstance().getUser_id())
.subscribeOn(Schedulers.io())//线程控制
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(PayMoneyEntity payMoneyEntity) {
payMoneyEntity.getMoney();
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
}
线程控制Scheduler 的原理:
http://blog.csdn.net/qq_28195645/article/details/52564494
在OnNext方法中我们就得到了经过解析后的实体类,可以getMoney了,享受长长的准备工作后的成果吧。
我自己在接入RR框架的过程中确实对自己的编程思想有非常大的提升,也希望更多的人能掌握RR框架的使用,写出更简洁优雅的代码。
以上,欢迎拍砖。