在实际的应用开发中,常用到的网络框架有OkHttp、Retrofit、RxJava+RxAndroid,每个框架都有自己的优点:例如OkHttp,因为其特有的拦截器责任链模式,可以拦截请求和响应;Retrofit内部封装OkHttp,它更高效在于使用注解封装Http请求,在之前Retrofit中也使用过;RxJava的优势在于它的操作符,事件的转换。
每个框架都有自己的优点,因此通过整合全部的请求框架,来实现多域名、多环境、结构清晰的网络模块,因此在项目封装网络请求模块势在必行。
1、基础理论
首先先介绍一下Http中请求和响应的报文格式。
(1)get请求报文格式
------第一部分:请求行
主要包括请求方法GET、URL(接口)、协议版本(Http1.0或者Http1.1)
------第二部分:请求头
Host:域名(www.xxxxx.xxx)、Connection(如果是Http1.1会默认是长连接 Keep Alive)、与Accept相关的字段(像Accept-Language、Accept-Encoding)…
状态码、状态码描述、协议版本
------第二部分:响应头
Server:服务器端的描述、Connection:长连接、响应的类型Content-type:json数据。。。。。。
------第三部分:响应体
装载响应数据
Post请求方式与get请求不同的是:请求报文格式中,请求的数据放在请求体中。
2、搭建网络模块
(1)Retrofit网络请求模块
implementation 'com.squareup.retrofit2:retrofit:2.7.1'
implementation 'com.squareup.okhttp:okhttp:2.7.5'
implementation 'com.squareup.retrofit2:converter-gson:2.7.1'
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constant.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
INetworkApi iNetworkApi = retrofit.create(INetworkApi.class);
Call<ArticleBean> call = iNetworkApi.getData(0);
call.enqueue(new Callback<ArticleBean>() {
@Override
public void onResponse(Call<ArticleBean> call, Response<ArticleBean> response) {
Log.e("TAG","response==="+response.body().toString());
}
@Override
public void onFailure(Call<ArticleBean> call, Throwable t) {
}
});
一般在应用中使用Retrofit就是这样的流程,在Model创建一个方法,请求这个方法在内部进行网络请求。
(2)添加日志拦截器
implementation 'com.squareup.okhttp3:logging-interceptor:4.4.0'
日志拦截器,主要是打印在网络请求时,请求和响应的过程,返回报文中的各个字段值。
public static OkHttpClient getOkHttpClient(){
OkHttpClient.Builder okhttpclient = new OkHttpClient.Builder();
if(iNetWorkRequiredInfo != null && iNetWorkRequiredInfo.isDebug()){
//http拦截,打印报文
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
okhttpclient.addInterceptor(loggingInterceptor);
}
//添加拦截器
okhttpclient.addInterceptor(new CommonRequestInterceptor(iNetWorkRequiredInfo));
return okhttpclient.build();
}
(3)添加请求和响应的拦截器
在实际开发过程中,通常需要在请求的头部添加字段或者截取响应中的某些字段,同样也需要使用OkHttp的拦截器实现。
public class CommonRequestInterceptor implements Interceptor {
private final INetWorkRequiredInfo netWorkRequiredInfo;
public CommonRequestInterceptor(INetWorkRequiredInfo netWorkRequiredInfo){
this.netWorkRequiredInfo = netWorkRequiredInfo;
}
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
//创建请求
Request.Builder builder = chain.request().newBuilder();
//添加请求头
builder.addHeader("Content-Type","application/json;charset=UTF-8");
return chain.proceed(builder.build());
}
}
public class CommonResponseInterceptor implements Interceptor {
private final INetWorkRequiredInfo requiredInfo;
public CommonResponseInterceptor(INetWorkRequiredInfo requiredInfo){
this.requiredInfo = requiredInfo;
}
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
//执行请求返回响应
Response response = chain.proceed(chain.request());
if(!response.header("Set-Cookie").isEmpty()){
//cookie字段有很多,只需要有JSessionId的字段
for (String header :
response.headers("Set-Cookie")) {
if (header.contains("JSESSIONID")) {
//将Cookie保存在本地
}
}
}
return response;
}
}
(4)支持RxJava
RxJava的优点就不必在此多说,看代码吧。
Observable<ArticleBean> observable = iNetworkApi.getDataByRxJava(0);
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ArticleBean>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ArticleBean articleBeanLiveData) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
(5)优化架构
在观察者订阅之后,有4个方法拖在后面,不太美观,因此可以抽取一个抽象的Observer类,然后只需要做请求成功或者失败的回调。
public abstract class BaseObserver<T> implements Observer<T> {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(T t) {
onSuccess(t);
}
@Override
public void onError(Throwable e) {
onFailed(e);
}
@Override
public void onComplete() {
}
protected abstract void onSuccess(T t);
protected abstract void onFailed(Throwable e);
}
.subscribe(new BaseObserver<ArticleBean>() {
@Override
protected void onSuccess(ArticleBean articleBeanLiveData) {
Log.e("TAG","livedata==="+articleBeanLiveData);
}
@Override
protected void onFailed(Throwable e) {
}
});
(6)业务接口
在网络层中,主要封装网络请求、OkHttp拦截器、日志拦截等操作,具体的业务还是得在app中完成,所以之前在网络层中的api接口以及javabean类都必须放到业务模块。
那么对于Retrofit对象,就需要拿到app当中使用。
//保存Retrofit对象
private static HashMap<String,Retrofit> retrofitMap = new HashMap<>();
不用单例设计模式,使用HashMap存储Retrofit对也可以,key就是BaseUrl + service的名字,在调用同一个api的时候,如果之前已经创建了Retrofit对象,那么就直接从集合中拿。
public static Retrofit getRetrofit(Class service) {
if(retrofitMap.get(Constant.BASE_URL + service.getName()) != null){
return retrofitMap.get(Constant.BASE_URL + service.getName());
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constant.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(getOkHttpClient())
.build();
//如果不存在,就将Retrofit添加到map集合
retrofitMap.put(Constant.BASE_URL + service.getName(),retrofit);
return retrofit;
}
//统一的接口调用
public static <T> T getService(Class<T> service){
return getRetrofit(service).create(service);
}
(7)线程调度的封装
在业务层调用api时,需要做线程切换。
NetWorkApi.getService(INetworkApi.class).getDataByRxJava(0)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BaseObserver<ArticleBean>() {
@Override
protected void onSuccess(ArticleBean articleBean) {
}
@Override
protected void onFailed(Throwable e) {
}
});
这一部分是可以抽出来,使用compose
来切换的,在compose
方法中,是传入的ObservableTransformer
,因此在网络模块中,创建一个线程调度的类。
//线程切换的封装
public static <T> ObservableTransformer<T,T> applyScheduler(final Observer<T> observer){
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource<T> apply(Observable<T> upstream) {
Observable<T> observable = upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
observable.subscribe(observer);
return observable;
}
};
}
在业务模块中使用compose就非常的简洁。
NetWorkApi.getService(INetworkApi.class).getDataByRxJava(0)
//做线程切换的封装
.compose(NetWorkApi.applyScheduler(new BaseObserver<ArticleBean>() {
@Override
protected void onSuccess(ArticleBean articleBean) {
}
@Override
protected void onFailed(Throwable e) {
}
}));