Retrofit+RxJava简单封装-让网络请求变得如此简单

img1

前提

我们公司处理网络请求是封装了okhttp,然后使用AsyncTask来然而异步网络请求,每次写一个网络请求都要创建一个AsyncTask文件,然后,处理一大堆的事件,虽然对AsyncTask进行了一层封装,但每次写都觉得不爽,而且AsyncTask又比较消耗系统资源,至从学习了Rxjava后,感觉,太爽了,一个链式调用就解决了以前很多代码还能实现的问题,既简洁,又阅读方便,最重要的它是函数响应式的编程,更符合现实生活的定义。然后呢,Retrofit出来也很久了,很早就听说过这个库非常好用,只是之前一直停留在1.9,没有出2.0的正式版,又一直没用,刚好今年年初,2.0出来了,呵呵,终于有机会来玩玩了。。.

目的

通过Rxjava与Retrofit的结合,让请求变得非常简单,而且在源头解决错误信息的处理,让获取数据的最终端只需要处理数据请求成功就可以了。。

文件构成

这里用到4个文件
1.RequestService

主要是对Retrofit的封装,以及token的处理

2.RequestBuilder

主要做的就是使用生成器对RequestService进行一层封装,对一些参数进行可配置

3.RequestApi

这里主要是retrofit写网络请求的地方,使用注解来完成相应的网络请求参数的封装

4.ErrorHandle

这里主要是对errorCode错误信息进行处理

1.RequestService处理

1.先来看看构造函数

RequestService(RequestBuilder builder) {  
    handleParams(builder);
    mErrorHandle = new ErrorHandle(mContext);
}

private void handleParams(RequestBuilder builder) {
    mContext = builder.getContext();
    if (null != builder.getRequestUrl())
        current_url = builder.getRequestUrl();
    if (null != builder.getRequestApi())
        current_req_api = builder.getRequestApi();
}

这里传入一个生成器,主要就是将外层的参数传进来进行处理;然后添加了ErrorHandle依赖

2.接下来就是比较重要的Retrofit的封装以及与requestApi接口进行绑定了

2.1创建Retrofit对象

Retrofit.Builder retrofit = new Retrofit.Builder().addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create(gson))
            .baseUrl(current_url);

// @formatter:off
final static Gson gson = new GsonBuilder()
        .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
        .serializeNulls()
        .enableComplexMapKeySerialization()
        .generateNonExecutableJson()
        .enableComplexMapKeySerialization()
        .create();
// @formatter:on

这里添加了retrofit对RxJava的支持,然后,给retrofit指定了一个自定义的gson来作为JSON的解析

2.2创建配置OKHTTP3.0并和Retrofit进行绑定

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);


    final OkHttpClient client = new okhttp3.OkHttpClient.Builder().addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Request newReq = request.newBuilder()
                    .addHeader("Cookie", getCookieFromLocal())
                    .addHeader("Content-Type", "application/json")
                    //其他统计参数
                    .addHeader("User-Agent", new HttpSPUtils().getHttpUADeviceInfo(mContext))
                    //加入 http 的其他的请求 头
                    .addHeader("device-info", new HttpSPUtils().getHttpHeadDeviceInfo(mContext))
                    .build();

            Response response = chain.proceed(newReq);

            Response newResponse = mErrorHandle.handleResponseError(response);

            saveCookieIfNeed(response);

            return newResponse;
        }
    }).addInterceptor(logging).build();

这里首先创建了HttpLogging拦截器并指定了打印log的级别,同样的通过添加拦截器的方式添加了相应的http请求头,token本地的保存,以及错误信息的拦截处理

2.3进行绑定

retrofit.client(client);

return retrofit.build().create(current_req_api);

这里首先将retrofit与okhttp3.0进行了绑定,作为http请求的解析工具,然后,再将retrofit与requestApi进行绑定,这里完成绑定被后,会返回此接口的一个实例,让使用者通过接口里定义的请求来得到相应的数据

2.RequestBuilder处理

这里主要是一个生成器,配置了一些可选的参数,调用者最终是通过调用此类来进行网络请求的。也就是此个网络封装只有这部分是暴露给用户的。

public class RequestBuilder<T> {

private Context context;
private String requestUrl;
private Class<T> requestApi;

public RequestBuilder(Context context) {
    this.context = context;
}

public Context getContext() {
    return context;
}

/**
 * 配置请求的baseurl,不配置为默认
 *
 * @param url
 * @return
 */
public RequestBuilder setRequestUrl(String url) {
    this.requestUrl = url;
    return this;
}


public String getRequestUrl() {
    return requestUrl;
}

public Class<T> getRequestApi() {
    return requestApi;
}


/**
 * 配置请求对应的接口class,不配置为默认
 *
 * @param requestApi
 * @return
 */
public RequestBuilder setRequestApi(Class<T> requestApi) {
    this.requestApi = requestApi;
    return this;
}

public RequestService build() {
    return new RequestService(this);
}
}

最后通过build()方法来创建了我们需要的RequestService

3.RequestApi处理

此文件主要是配置一些请求的参数,并对返回对象进行设置

@GET("xiuWord/getXiuWordDataList")
Observable<QueryInfo> getCommandQueryInfo(@Query("query") String url);

这里定义了一个Get请求方法,指定了url路径,并添加了query参数来请求数据,并将返回的数据直接封装到了Observable里让调用者可以非常方便的使用Rxjava来进行对数据的处理及ui的展示

4.ErrorHandle错误处理

这里主要是将okhttp里的拦堆器里的错误放到一个文件里来进行单独的维护,当然这里的错误呢,不只是http层面的错误处理,还包括业务逻辑上的错误处理,很多时候就是toast错误提示,最典型的处理就是有些公司不允许多台移动终端共用一个帐号的情况。只需要在上层一个地方处理,就可以全局能用,这个好处省去了,在很多个网页都要单独做判断的情况,非常的好用,实用。

当然这里有个问题就是统一跳转到哪里?
一般情况下我们会选择直接跳转到用户中心,这是一种比较安全的跳转,如果继续留在当前页,会出现一些麻烦。
跳转到用户中心也有一个问题?
就是当你从用户中心按返回键的时候,之前的页面还是存在的,容易导致没请求到数据页面卡在那里或者是空指针什么的。这里可以把用户中心的Activity设置成singTask模式。

处理到这里也就基本完成了简单的网络请求的封装了。

5.可能出现问题处理

      现在很多架构都是分Module来进行开发的了,我们公司也是这样的情况,那么就会有一个问题,就是Module之前的通信问题。就拿上面全局跳转来说,我们的网络请求一般是放在BaseModule里面来被全局所依赖,也就是说我们全局的跳转是放在最顶层的,而一般我们像用户中心这样子Activity是放在主Module的,那么,顶层的base是没有办法访问主Module里的东西的。

那么Module之间的通信到底要怎么做呢?
      这里有两种做法,一种是:使用广播来进行通信,第二种就是:使用RxBus,也就是事件总线的Rx支持来进行通信。这里我推荐第二种。主要是广播是比较耗费系统资源的,不怎么友好,最重要的是,广播会有延迟,特别是在一些国产手机里面,我之前的OPPO Find 7就非常明显。

简单封装RxBus
在这里我使用Rxjava里的Subject来简单的封装了一个RxBus,可以用来传对象

public class RxBus {
private static RxBus instance;

private Subject bus = null;

public RxBus() {
    bus = new SerializedSubject<>(PublishSubject.create());
}

public static RxBus getInstance() {
    if (instance == null) {
        synchronized (RxBus.class) {
            if (instance == null) {
                instance = new RxBus();
            }
        }
    }
    return instance;
}

//提供一个新的事件
public void post(Object o) {
    bus.onNext(o);
}

//根据传递的eventType类型 返回特定类型的eventType给观察者
public <T extends Object> Observable<T> toObservable(final Class<T> eventType) {

    return bus.filter(new Func1() {
        @Override
        public Boolean call(Object o) {
            return eventType.isInstance(o);
        }
    })
            .cast(eventType);
}


}

这个简单的RxBus已经被我用来处理上面全局跳转用户中心了。当然在全局使用,Rxbus的注册需要写在Application里的.

好了,今天的网络封装就写到这里的。