RxJava+Retrofit+OkHttp组合在网络请求中的简单配置

本篇文章不会介绍这一组合的使用方法,网上已经有很多好的教程。
这里主要讲一下在网络调用中的个人使用心得,主要实现以下4个目标

  1. 请求前判断网络是否连接
  2. 打印请求和响应,方便调试
  3. 抛出正确请求异常
  4. 统一判断返回结果

    主要用到了OkHttp的拦截器Interceptor.

判断网络是否连接

在网络请求前,最好能判断用户的网络连接状况,如果没有连接网络,则直接不发出请求,并抛出异常。
声明mNetInterceptor拦截器:

 private final Interceptor mNetInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            BaseManager.isThereInternetConnection();
            return chain.proceed(chain.request());
        }
    };

其中isThereInternetConnection方法如下:

public static void isThereInternetConnection() {
        ConnectivityManager connectivityManager =
                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        if (networkInfo == null || !networkInfo.isConnectedOrConnecting()) {
            throw new RuntimeException("连接失败,请检查您的网络连接!");
        }
    }

当然这个方法也可以换个写法,只要相应地更改mNetInterceptor的写法就可以了。

打印请求和响应,方便调试

在调试时,我们通常希望能打印出请求信息和响应信息,方便我们发现问题,查看数据等。
这也简单,可以声明另一个mLoggingInterceptor拦截器:

private final Interceptor mLoggingInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Response response = null;
            String bodyString = null;
            Request request = chain.request();
            long t1 = System.nanoTime();
            LogUtil.i(TAG, String.format("request to:%s", request.url().toString()));
            response = chain.proceed(request);
            bodyString = response.body().string(); 
            long t2 = System.nanoTime();
            LogUtil.i(TAG, String.format(Locale.getDefault(), "response from %s in %.1fms",
            response.request().url(), (t2 - t1) / 1e6d));
            Logger.t(TAG).json(bodyString);

            return response.newBuilder()
                    .body(ResponseBody.create(response.body().contentType(), bodyString))
                    .build();
        }
    };

这里我打印了请求的完整url,返回的url及json数据。
这里要注意:因为the response body is a one-shot value that may be consumed only once,body只能用一次,我们打印了body的信息后,只能这样返回:

return response.newBuilder()
                    .body(ResponseBody.create(response.body().contentType(), bodyString))
                    .build();

具体可以查看OkHttp的issues,大神JakeWharton也对此解答过,具体地址下次找到了再放上来~

抛出正确请求异常

有时候由于各种原因请求失败,我们需要抛出适当的信息提示用户,同时调试下我打印了失败的状态码,修改上面的mLoggingInterceptor如下:

private final Interceptor mLoggingInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Response response = null;
            String bodyString = null;
            try {
                Request request = chain.request();
                long t1 = System.nanoTime();
                LogUtil.i(TAG, String.format("request to:%s", request.url().toString()));
                response = chain.proceed(request);
                bodyString = response.body().string();
                if (response.code() == HttpStatus.SC_OK) {
                    long t2 = System.nanoTime();
                    LogUtil.i(TAG, String.format(Locale.getDefault(), "response from %s in %.1fms",
                            response.request().url(), (t2 - t1) / 1e6d));
                    Logger.t(TAG).json(bodyString);
                } else {
                    LogUtil.i(TAG, String.format("http响应不成功,响应码为:%s", response.code()));
                    throw new RuntimeException("服务器响应不成功(′⌒`)");
                }
            } catch (IOException e) {
                throw new RuntimeException("服务器好像挂了(′⌒`)");
            }
            return response.newBuilder()
                    .body(ResponseBody.create(response.body().contentType(), bodyString))
                    .build();
        }
    };
统一判断返回结果

一般返回的都是json格式数据,很多可能像下面这样:

 {
  "code": 0,
  "message": "成功",
  "data": {
    "title": "google",
    "description": "great company",
    "like": "android",
    "url": "http://google.com"
  }
}

其中code是状态码,它为0时请求成功,不为0时请求失败,data中才是真正的业务数据。
如果我们能统一对code判断,成功时取出data,失败时显示错误信息,岂不是很爽?

新建RxHttpResult类如下:

public class RxHttpResult<T> implements Func1<ResultEntity<T>, Observable<T>> {
    @Override
    public Observable<T> call(final ResultEntity<T> resultEntity) {
        return Observable.create(new Observable.OnSubscribe<T>() {
            @Override
            public void call(Subscriber<? super T> subscriber) {
                if (resultEntity.isSuccess()) {
                    subscriber.onNext(resultEntity.getData());
                    subscriber.onCompleted();
                } else {
                    subscriber.onError(new RuntimeException(resultEntity.getMessage()));
                }
            }
        });
    }
}

每个接口返回的数据都写成泛型类ResultEntity<T>其中resultEntity.isSuccess()判断code是否为0,接着调用观察者的相应方法。

在这里,如果是返回是失败,我的处理都是弹出失败信息,这可以统一处理,不用每次都写一遍,新建泛型类RxHttpObserver

public abstract class RxHttpObserver<T> implements Observer<T> {


    @Override
    public void onError(Throwable e) {
        ToastUtils.displayCustomToast(e.getMessage(), Gravity.CENTER);
    }

}

这里只重写了onError方法,调用时只需重写onNextonCompleted方法就可以了。
如果失败时要增加或修改处理方式,再重写onError方法。
当然你也可以根据自己的需求定制,这只是一个思路吧。

OkHttp配置

按照以上实现,最后我们的OkHttp就变成这样了:

   mOkHttpClient = new OkHttpClient.Builder()
                            .connectTimeout(30, TimeUnit.SECONDS)
                            .readTimeout(30, TimeUnit.SECONDS)
                            .writeTimeout(30, TimeUnit.SECONDS)
                            .addInterceptor(mNetInterceptor)
                            .addInterceptor(mLoggingInterceptor)
                            .build();

再将 mOkHttpClient设为Retrofit的client就可以了。
注意:两个拦截器的添加顺序不能搞错,只有在网络连接的情况下才需要执行请求并打印日志。

调用示例

配置好之后,就可以来调用一下啦,如下:

mSubscription = HttpManager.Instance.getTestApi().getGoogle()
                .flatMap(new RxHttpResult<Google >())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new RxHttpObserver<Google >() {
                    @Override
                    public void onCompleted() {
                       //成功完成,去庆祝一下
                    }

                    @Override
                    public void onNext(Google google) {
                       //数据来了,开始干活
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                       //出错了……除了弹出提示,我还想哈哈哈
                       //这个方法也可以不重写哦~
                    }
                });

使用.flatMap(new RxHttpResult<Google >())统一处理返回结果。
使用.subscribe(new RxHttpObserver<Google >() {...}统一弹出错误信息。

注意:mSubscription要及时取消订阅,以免内存泄漏。

这样一套下来,有木有感觉神清气爽,神采飞扬,一次网络请求代码写的爽、打印看得爽、简直不要太爽~!哈哈哈

当然如果你有更好的方法,欢迎留言讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值