您的位置:首页 > 理论基础 > 计算机网络

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

2016-10-22 15:18 369 查看
本篇文章不会介绍这一组合的使用方法,网上已经有很多好的教程。

这里主要讲一下在网络调用中的个人使用心得,主要实现以下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
方法,调用时只需重写
onNext
onCompleted
方法就可以了。

如果失败时要增加或修改处理方式,再重写
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
要及时取消订阅,以免内存泄漏。

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

当然如果你有更好的方法,欢迎留言讨论。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: