Nowadays, the combined use of RxJava and Retrofit is estimated to be quite common, and it has been used in my own work all the time. In the process of using it, we will package it and use it. There are also many packaged projects on GitHub that can be used directly. In fact, the secondary packaging of open source frameworks is sometimes more or less in the process of packaging different business logic. Some are different, it is recommended to package and use it by yourself. This will not only improve your understanding of the original framework, but also improve your packaging capabilities. It is easier to start if you need to make changes during the work process. Well, without further ado, here is a simple sample for your reference.
add dependencies
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'io.reactivex.rxjava2:rxjava:2.x.y'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
I don't want to say more about adding dependencies. I think everyone knows, but when I first came into contact with this knowledge, I wonder if anyone will find and add some dependencies when reading online articles? For example: com.squareup.retrofit2:converter-gson:2.3.0
we want to add a GsonConverter
dependency. Will it be confusing for those who are new to this knowledge and who don't often visit GitHub? Regardless of whether it will or not, anyway, I was really confused when I first came into contact with it. Here is a reminder for those who have been confused, we can view the corresponding dependencies by opening the subfile of the project on GitHub. For example, in the Retrofit project on GitHub: retrofit/retrofit-converters/gson/
you can view the corresponding GsonConverter
dependencies under this path.
Encapsulate Retrofit (singleton mode)
public class HttpRequest {
public static final long CONNECTTIME = 30000;
public static final String BASE_URL = "http://jxhdapi.ooowin.com/";
private ApiService apiService;
public HttpRequest() {
//添加日志拦截器
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Log.d("TAG", "==========" + message);
}
}).setLevel(HttpLoggingInterceptor.Level.BODY);
//获取OkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(CONNECTTIME, TimeUnit.MICROSECONDS)
.readTimeout(CONNECTTIME,TimeUnit.MICROSECONDS)
.writeTimeout(CONNECTTIME,TimeUnit.MICROSECONDS)
.addInterceptor(interceptor)
.addNetworkInterceptor(new HttpHeaderInterceptor())
.build();
//初始化Retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
apiService = retrofit.create(ApiService.class);
}
// 创建单例
private static class SingletonHolder {
private static final HttpRequest INSTANCE = new HttpRequest();
}
public static ApiService getApi(){
return SingletonHolder.INSTANCE.apiService;
}
}
Here we can see that two interceptors have been added: the log interceptor and the network request Header interceptor. We all know that for Retrofit, we can directly convert it GsonConverter
into an entity class, but sometimes we want to get its json To view the data, we can implement it by adding a log interceptor at this time, but we must set setLevel
the method for it, and the data printed out by setting different attributes is different. As for adding a header interceptor, I think everyone should know that the headers required by the interface in normal work are the same, so we need to add them uniformly:
public class HttpHeaderInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request build = request.newBuilder()
// .addHeader("","") 添加header
.build();
return chain.proceed(build);
}
}
encapsulation entity class
{
"code": 1,
"msg": "操作成功",
"data": {······}
}
Usually the json data we get from the server is like the above, and some returned field content formats are fixed, such as: code and msg. Some are uncertain, such as: data. At this time, we need to perform secondary processing on it. We can write a base class:
public class BaseBean<T> {
private int code;
private String msg;
private T data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
Use generics to represent data in an uncertain format in data. Here, a data interface for obtaining all provinces in the country is used for testing:
public interface ApiService {
//获取省列表
@GET("common/areas")
Flowable<BaseBean<List<Province>>> province();
}
After the entity class is encapsulated, we can test it:
HttpRequest.getApi()
.province()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<BaseBean<List<Province>>>() {
@Override
public void onSubscribe(Subscription s) {
}
@Override
public void onNext(BaseBean<List<Province>> listBaseBean) {
}
@Override
public void onError(Throwable t) {
}
@Override
public void onComplete() {
}
});
}
Through the above code, it is not difficult to see that this is the effect of encapsulation, but we will find that we have to add a scheduler and rewrite Subscriber
several methods every time for such a request? Wouldn't that still be cumbersome. Yes, then we will encapsulate these.
Use the compose operator
public class SchedulersHelper implements FlowableTransformer{
@Override
public Publisher apply(Flowable upstream) {
return upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
}
Using the compose operator can directly operate on the current Flowable, so we can naturally add the operation of switching threads here. The next step is Subscriber for encapsulation.
Package Subscriber
public abstract class MySubscriber<T> implements Subscriber<T>{
@Override
public void onSubscribe(Subscription s) {
s.request(Long.MAX_VALUE);
showLoading();
}
@Override
public void onNext(T t) {
//code为1代表服务器返回成功的数据
if (((BaseBean)t).getCode() == 1) {
//成功后返回data数据进行处理即可
onSuccess((T) ((BaseBean) t).getData());
}else {
//处理服务器返回错误code
}
}
@Override
public void onComplete() {
finishLoading();
}
@Override
public void onError(Throwable t) {
finishLoading();
//处理网络异常
Log.d("TAG","=========" + t);
}
protected abstract void onSuccess(T t);
protected abstract void showLoading();
protected abstract void finishLoading();
}
As shown above, we judge whether it is successful according to the code returned by the server, and then send the data data. The error codes returned by the server and network request errors can all be processed here in a unified manner. Then we go to test the interface.
test
HttpRequest.getApi().province()
.compose(new SchedulersHelper())
.subscribe(new MySubscriber() {
@Override
protected void onSuccess(Object o) {
}
@Override
protected void showLoading() {
}
@Override
protected void finishLoading() {
}
});
It can be seen that the operation process has become very simple. We don’t need to put showLoading()
these finishLoading()
two methods here. This is written in it for the convenience of testing.
Finish
At this point, the encapsulation of RxJava + Retrofit is over. This is a very simple encapsulation process without using too much complicated logic. It is relatively easy to understand, and the completeness of the package may not be very high. You can use it as a reference and use your own understanding to better package it. I wrote a simple MVP base class before, and I put it in the previous project for this encapsulation process. It constitutes a simple, easy-to-understand and easy-to-use: a small demo of RxJava + Retrofit + MVP, which is placed on GitHub. You can check RxRetrofitMvp . If you think it is helpful to you, please give it a star, hahaha!