前言:
近些年很火的Retrofit+RxJava+OkHttp网络请求框架,功能强大,结构合理,使用简单方便。后面还会给大家发自己整理过的Retrofit和RxJava、RxAndroid和RxBus。希望大家点一下关注,让我这个懒癌患者有动力继续写下去!
本篇分三个部分:基础篇、封装篇和自己项目使用篇,项目是自己公司的APP提取的,文章偏长可以分三部分一点点看,当初看了很多优秀的文章然后自己在整理写在印象笔记中。
感谢大佬们的学习参考文章:
扔物线:http://gank.io/post/560e15be2dca930e00da1083
依然范特西 :https://www.jianshu.com/p/5bc866b9cbb9
拉丁吴:https://juejin.im/post/580103f20e3dd90057fc3e6d
玉刚说:https://juejin.im/post/5b17560e6fb9a01e2862246f
最新更新:7.11,更新内容是升级版本替换成RxJava2,修改了一些语法。
Github地址:https://github.com/bigeyechou/NetWorkFrame
简单介绍Retrofit、OKHttp和RxJava之间的关系:
- Retrofit:Retrofit是Square公司开发的一款针对Android 网络请求的框架(底层默认是基于OkHttp 实现)。
- OkHttp:也是Square公司的一款开源的网络请求库。
- RxJava :"a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。RxJava使异步操作变得非常简单。
各自职责:Retrofit 负责 请求的数据 和 请求的结果,使用 接口的方式 呈现,OkHttp 负责请求的过程,RxJava 负责异步,各种线程之间的切换。
基础篇:
一、Retrofit写一个网络请求:
1.引入Retrofit的包,在build.gradle文件中添加如下配置:
compile 'com.squareup.retrofit2:retrofit:2.3.0'//导入retrofit
compile 'com.google.code.gson:gson:2.6.2'//Gson 库
//下面两个是RxJava 和 RxAndroid
compile 'io.reactivex.rxjava2:rxandroid:2.0.2'
compile 'io.reactivex.rxjava2:rxjava:2.x.y'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'//转换器,请求结果转换成Model
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//配合Rxjava 使用
2.创建一个Retrofit 实例,并且完成相关的配置:
配置了接口的 BASE_URL 和一个 converter , GsonConverterFactory 是默认提供的 Gson转换器。
public static final String BASE_URL = "https://api.douban.com/v2/movie/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
3.创建一个接口:
定义了一个方法 getTop250 ,使用 get请求方式,加上@GET 标签,标签后面是这个接口的 尾址top250,完整的地址应该是 baseUrl+尾址 ,参数 使用@Query标签,如果参数多的话可以用@QueryMap标 签,接收一个Map。
使用 POST 请求方式时,只需要更改方法定义的标签,用 @POST 标签,参数标签用 @Field 或者 @Body 或者 FieldMap
public interface MovieService {
//获取豆瓣Top250 榜单
@GET("top250")
Call<MovieSubject> getTop250 (@Query("start") int start , @Query("count") int count);
(“top250”)
Call<MovieSubject> getTop250 (@Field(“start”) int start , @Field(“count”) int count);
}
使用 POST 方式时需要注意两点:
- 必须加上 @FormUrlEncoded标签,否则会抛异常。
- 必须要有参数,否则会抛异常, 源码抛异常的地方如下:
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
4.用 Retrofit 创建 接口实例 MoiveService 并且调用接口中的方法进行网络请求:
异步方式请求:
//获取接口实例
MovieService movieService = retrofit.create(MovieService.class);
//调用方法得到一个Call
Call<MovieSubject> call = movieService.getTop250(0,20);
//进行网络请求
call.enqueue(new Callback<MovieSubject>() {
@Override
public void onResponse(Call<MovieSubject> call, Response<MovieSubject> response) {
mMovieAdapter.setMovies(response.body().subjects);
mMovieAdapter.notifyDataSetChanged();
}
@Override
public void onFailure(Call<MovieSubject> call, Throwable t) {
t.printStackTrace();
}
});
同步方式请求: 返回一个Response
Response<MovieSubject> response = call.execute();
二,配合RxJava 使用:
- 更改定义的接口,返回值不再是一个 Call ,而是返回的一个 Observble:
public interface MovieService {
//获取豆瓣Top250 榜单
@GET("top250")
Observable<MovieSubject> getTop250(@Query("start") int start, @Query("count")int count);
}
2.创建 Retrofit 的时候添加如下代码:
addCallAdapterFactory(RxJava2CallAdapterFactory.create())
3.添加转换器Converter(将 json 转为 JavaBean):
addConverterFactory(GsonConverterFactory.create())
举实际项目中使用的例子:
retrofit = new Retrofit.Builder()
.client(okHttpBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(BASE_URL)
.build();
4.Activity 或者 Fragment 中传入 DisposableObserver 建立订阅关系:
Subscription subscription = movieService.getTop250(0,20)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableObserver<MovieSubject>() {
@Override
public void onComplete() {
}
public void onError(Throwable e) {
}
public void onNext(MovieSubject movieSubject) {
mMovieAdapter.setMovies(movieSubject.subjects);
mMovieAdapter.notifyDataSetChanged();
}
});
5.加入RxJava的好处:
- 加入 RxJava 后的网络请求,返回不再是一个 Call ,而是一个 Observable。
- 在Activity / Fragment 中传入一个Subscriber 建立订阅关系,就可以在 onNext 中处理结果了。
- RxJava 的好处是帮我处理 线程之间的切换,我们可以在指定 订阅的在哪个线程,观察在哪个线程。
- 可以 通过操作符 进行数据变换。
- 整个过程都是链式的,简化逻辑。其中FlatMap 操作符 还可以解除多层嵌套的问题。
RxJava 很强大,能帮我处理很多复杂的场景,如果熟练使用的话,那么能提升我们的开发效率。
三,加入 OkHttp 配置:
通过OkHttpClient 可以配置很多东西,比如 链接超时时间,缓存,拦截器 等等。代码如下:
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接 超时时间
builder.writeTimeout(DEFAULT_TIME_OUT,TimeUnit.SECONDS);//写操作 超时时间
builder.readTimeout(DEFAULT_TIME_OUT,TimeUnit.SECONDS);//读操作 超时时间
builder.retryOnConnectionFailure(true);//错误重连
// 添加公共参数拦截器
BasicParamsInterceptor basicParamsInterceptor = new BasicParamsInterceptor.Builder()
.addHeaderParam(“userName”,"")//添加公共参数
.addHeaderParam(“device”,"")
.build();
builder.addInterceptor(basicParamsInterceptor);
// 创建Retrofit
mRetrofit = new Retrofit.Builder()
.client(builder.build())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(ApiConfig.BASE_URL)
.build();
列举项目中用到的如下:
//项目中设置头信息
Interceptor headerInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Request.Builder requestBuilder = originalRequest.newBuilder()
.addHeader("Accept-Encoding", "gzip")
.addHeader("Accept", "application/json")
.addHeader("Content-Type", "application/json; charset=utf-8")
.method(originalRequest.method(), originalRequest.body());
requestBuilder.addHeader("Authorization", "Bearer " + BaseConstant.TOKEN);//添加请求头信息,服务器进行token有效性验证
Request request = requestBuilder.build();
return chain.proceed(request);
}
};
okHttpBuilder.addInterceptor(headerInterceptor);
//项目中创建Retrofit
retrofit = new Retrofit.Builder()
.client(okHttpBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(BASE_URL)
.build();
httpService = retrofit.create(HttpService.class);
封装篇
一,创建一个 统一生成接口实例的管理类 RetrofitServiceManager
创建了一个 RetrofitServiceManager 类,该类采用 单例模式,在 私有的 构造方法中,生成了 Retrofit 实例,并配置了OkHttpClient 和一些 公共配置。
提供了一个create()方法,生成 接口实例,接收 Class泛型。
代码如下:
public class RetrofitServiceManager {
private static final int DEFAULT_TIME_OUT = 5;//超时时间 5s
private static final int DEFAULT_READ_TIME_OUT = 10;
private Retrofit mRetrofit;
private RetrofitServiceManager(){
// 创建 OKHttpClient
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时时间
builder.writeTimeout(DEFAULT_READ_TIME_OUT,TimeUnit.SECONDS);//写操作 超时时间
builder.readTimeout(DEFAULT_READ_TIME_OUT,TimeUnit.SECONDS);//读操作超时时间
<span class="hljs-comment">// 添加公共参数拦截器 </span>
HttpCommonInterceptor commonInterceptor = <span class="hljs-keyword">new</span> HttpCommonInterceptor.Builder()
.addHeaderParams(<span class="hljs-string">"paltform"</span>,<span class="hljs-string">"android"</span>)
.addHeaderParams(<span class="hljs-string">"userToken"</span>,<span class="hljs-string">"1234343434dfdfd3434"</span>)
.addHeaderParams(<span class="hljs-string">"userId"</span>,<span class="hljs-string">"123445"</span>)
.build();
builder.addInterceptor(commonInterceptor);
<span class="hljs-comment">// 创建Retrofit </span>
mRetrofit = <span class="hljs-keyword">new</span> Retrofit.Builder()
.client(builder.build())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(ApiConfig.BASE_URL)
.build();
}
private static class SingletonHolder{
private static final RetrofitServiceManager INSTANCE = new RetrofitServiceManager();
}
<span class="hljs-comment">/**
* 获取RetrofitServiceManager
* <span class="hljs-doctag">@return</span>
*/</span>
public static RetrofitServiceManager getInstance(){
return SingletonHolder.INSTANCE;
}
/**
* 获取对应的Service
* @param service Service 的 class
* @param <T>
* @return
*/
public <T> T create(Class<T> service){
return mRetrofit.create(service);
}
}
接口实例Service都可以用这个来生成,代码如下:
mMovieService = RetrofitServiceManager.getInstance().create(MovieService.class);
二,创建接口,通过第一步获取实例
有了可以获取接口实例的方法,然后创建一个接口,代码如下:
public interface MovieService{
//获取豆瓣Top250 榜单
@GET("top250")
Observable<MovieSubject> getTop250(@Query("start") int start, @Query("count") int count);
("/x3/weather")
Call<String> getWeather(@Field(“cityId”) String cityId, @Field(“key”) String key);
}
三,创建一个业务Loader ,如XXXLoder,获取Observable并处理相关业务
创建 Loader 的原因:每一个Api 都写一个接口很麻烦,因此就把 请求逻辑 封装在 一个业务Loader 里面,一个 Loader 里面可以处理多个Api 接口。代码如下:
public class MovieLoader extends ObjectLoader {
private MovieService mMovieService;
public MovieLoader(){
mMovieService = RetrofitServiceManager.getInstance().create(MovieService.class);
}
/**
* 获取电影列表
* @param start
* @param count
* @return
*/
public Observable<List<Movie>> getMovie(int start, int count){
return observe(mMovieService.getTop250(start , count)).map(new Func1<MovieSubject, List<Movie>>() {
@Override
public List<Movie> call(MovieSubject movieSubject) {
return movieSubject.subjects;
}
});
}
public Observable<String> getWeatherList(String cityId,String key){
return observe(mMovieService.getWeather(cityId , key)).map(new Func1<String , String>() {
public String call(String s) {
//可以处理对应的逻辑后在返回
return s;
}
});
}
public interface MovieService{
//获取豆瓣Top250 榜单
(“top250”)
Observable<MovieSubject> getTop250(@Query(“start”) int start, @Query(“count”)int count);
<span class="hljs-meta">@FormUrlEncoded</span>
<span class="hljs-meta">@POST</span>(<span class="hljs-string">"/x3/weather"</span>)
<span class="hljs-function">Call<String> <span class="hljs-title">getWeather</span><span class="hljs-params">(@Field(<span class="hljs-string">"cityId"</span>)</span> String cityId, @<span class="hljs-title">Field</span><span class="hljs-params">(<span class="hljs-string">"key"</span>)</span> String key)</span>;
}
}
创建一个MovieLoader,构造方法中生成了mHttpService,而 Service 中可以定义和业务相关的多个api,比如:例子中的HttpService中,
可以定义和电影相关的多个api,获取电影列表、获取电影详情、搜索电影等api,就不用定义多个接口了。
MovieLoader 是从 ObjectLoader 中继承下来的,ObjectLoader 提取了一些公共的操作。代码如下:
/**
- 将一些重复的操作提出来,放到父类以免Loader 里每个接口都有重复代码
/
public class ObjectLoader {
/* - @param observable
- @param <T>
- @return
*/
protected <T> Observable<T> observe(Observable<T> observable){
return observable
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
}
四,Activity/Fragment 中的调用
创建Loader实例:
mMovieLoader = new MovieLoader();
通过Loader 调用方法获取结果,代码如下:
/**
* 获取电影列表
*/
private void getMovieList(){
mMovieLoader.getMovie(0,10).subscribe(new Action1<List<Movie>>() {
@Override
public void call(List<Movie> movies) {
mMovieAdapter.setMovies(movies);
mMovieAdapter.notifyDataSetChanged();
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Log.e("TAG","error message:"+throwable.getMessage());
}
});
}
五,统一处理结果和错误
1.统一处理请求结果:
现实项目中,所有接口的返回结果都是同一格式,如:
{
"status": 200,
"message": "成功",
"data": {}
}
在请求api 接口的时候,只关心想要的数据,也就上面的 data{ },其他的东西不太关心,请求失败 的时候可以根据 status 判断进行 错误处理。
包装返回结果:首先需要根据服务端定义的 JSON 结构创建一个 BaseResponse 类,代码如下:
/**
* 网络请求结果 基类
*/
public class BaseResponse<T> {
public int status;
public String message;
public T data;
public boolean isSuccess(){
return status == 200;
}
}
有了统一的格式数据后,我们需要 剥离出data{ }返回给 上层调用者,创建一个 PayLoad 类,代码如下:
/**
* 剥离 最终数据
*/
public class PayLoad<T> implements Func1<BaseResponse<T>{
@Override
public T call(BaseResponse<T> tBaseResponse) {//获取数据失败时,包装一个Fault 抛给上层处理错误
if(!tBaseResponse.isSuccess()){
throw new Fault(tBaseResponse.status,tBaseResponse.message);
}
return tBaseResponse.data;
}
}
PayLoad 继承自 Func1,接收一个BaseResponse<T> , 就是接口返回的 JSON 数据结构,返回的是 T,就是data{ },判断是否请求成功,请求成功 返回Data,请求失败 包装成一个 Fault 返回给上层统一处理错误。
在Loader类里面获取结果后,通过map 操作符剥离数据。代码如下:
public Observable<List<Movie>> getMovie(int start, int count){
return observe(mMovieService.getTop250(start,count))
.map(new PayLoad<BaseResponse<List<Movie>>());
}
2.统一处理错误:
在PayLoad 类里面,请求失败时,抛出了一个Fault 异常给上层,我在Activity/Fragment 中拿到这个异常,然后判断错误码,进行异常处理。在onError () 中添加。
对应 错误码 处理 相应的错误,代码如下:
public void call(Throwable throwable) {
Log.e("TAG","error message:"+throwable.getMessage());
if(throwable instanceof Fault){
Fault fault = (Fault) throwable;
if(fault.getErrorCode() == 404){
//错误处理
}else if(fault.getErrorCode() == 500){
//错误处理
}else if(fault.getErrorCode() == 501){
//错误处理
}
}
}
六,添加公共参数
实际项目中,每个接口都有一些基本的相同的参数,我们称之为公共参数,比如:userId、userToken、userName、deviceId等等,我们不必每个接口都去写,可以写一个拦截器,在拦截器里面拦截请求,为每个请求都添加相同的公共参数。
拦截器代码如下:
/*
* 拦截器
*
* 向请求头里添加公共参数
*/
public class HttpCommonInterceptor implements Interceptor {
private Map<String,String> mHeaderParamsMap = new HashMap<>();
public HttpCommonInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
Log.d("HttpCommonInterceptor","add common params");
Request oldRequest = chain.request();
// 添加新的参数,添加到url 中
/*HttpUrl.Builder authorizedUrlBuilder = oldRequest.url().newBuilder()
.scheme(oldRequest.url().scheme())
.host(oldRequest.url().host());*/
<span class="hljs-comment">// 新的请求 </span>
Request.Builder requestBuilder = oldRequest.newBuilder();
requestBuilder.method(oldRequest.method(), oldRequest.body());
<span class="hljs-comment">//添加公共参数,添加到header中 </span>
<span class="hljs-keyword">if</span>(mHeaderParamsMap.size() > <span class="hljs-number">0</span>){
<span class="hljs-keyword">for</span>(Map.Entry<String,String> params:mHeaderParamsMap.entrySet()){
requestBuilder.header(params.getKey(),params.getValue());
}
}
Request newRequest = requestBuilder.build();
return chain.proceed(newRequest);
}
public static class Builder{
HttpCommonInterceptor mHttpCommonInterceptor;
public Builder(){
mHttpCommonInterceptor = new HttpCommonInterceptor();
}
public Builder addHeaderParams(String key, String value){
mHttpCommonInterceptor.mHeaderParamsMap.put(key,value);
return this;
}
public Builder addHeaderParams(String key, int value){
return addHeaderParams(key, String.valueOf(value));
}
public Builder addHeaderParams(String key, float value){
return addHeaderParams(key, String.valueOf(value));
}
public Builder addHeaderParams(String key, long value){
return addHeaderParams(key, String.valueOf(value));
}
public Builder addHeaderParams(String key, double value){
return addHeaderParams(key, String.valueOf(value));
}
public HttpCommonInterceptor build(){
return mHttpCommonInterceptor;
}
}
}
以上就是添加公共参数的拦截器,在 RetrofitServiceManager 类里面加入OkHttpClient 配置就好了。
代码如下:
// 添加公共参数拦截器
HttpCommonInterceptor commonInterceptor = new HttpCommonInterceptor.Builder()
.addHeaderParams("paltform","android")
.addHeaderParams("userToken","1234343434dfdfd3434")
.addHeaderParams("userId","123445")
.build();
builder.addInterceptor(commonInterceptor);
项目使用篇 ----->插入广告!本项目来源于金融研习社App,金融理财类的在线教育
项目是基于RxJava1
1.引入依赖:
compile 'com.google.code.gson:gson:2.6.2'//导入Gson 库
//导入RxJava 和 RxAndroid
compile 'io.reactivex.rxjava2:rxandroid:2.0.2'
compile 'io.reactivex.rxjava2:rxjava:2.x.y'
compile 'com.squareup.retrofit2:retrofit:2.3.0'//导入retrofit
compile 'com.squareup.retrofit2:converter-gson:2.3.0'//转换器,请求结果转换成Model
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//配合Rxjava 使用
compile 'com.squareup.okhttp3:logging-interceptor:3.8.1'//添加HttpLoggingInterceptor进行调试
2.创建一个HttpService接口:
public interface HttpService {
/**
* 获取用户详细资料
*/
@POST("api/XXX/GetUserAllDetails")
Observable<ResponseBody> getUserAllDetails(@Body GetUserAllDetailsRequestBean bean);
/**
- @param apkUrl 下载地址
*/
()
Call<ResponseBody> downloadNewApk(@Url String apkUrl);
/**
- 获取推广大使分享图片
*/
(“api/XXX/InvitedImage”)
Observable<ResponseBody> getInvitedImage(@QueryMap Map<String, Object> map);
}
3.创建http请求类,并在里面初始化并配置Retrofit和OkHttp:
public class HttpMethods {
public String TAG = "HttpMethods";
public static final String CACHE_NAME = "xxx";
public static String BASE_URL = URLConstant.BASE_URL;
private static final int DEFAULT_CONNECT_TIMEOUT = 30;
private static final int DEFAULT_WRITE_TIMEOUT = 30;
private static final int DEFAULT_READ_TIMEOUT = 30;
private Retrofit retrofit;
private HttpService httpService;
/**
* 请求失败重连次数
*/
private int RETRY_COUNT = 0;
private OkHttpClient.Builder okHttpBuilder;
<span class="hljs-comment">//构造方法私有</span>
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">HttpMethods</span><span class="hljs-params">()</span> </span>{
<span class="hljs-comment">//手动创建一个OkHttpClient并设置超时时间</span>
okHttpBuilder = <span class="hljs-keyword">new</span> OkHttpClient.Builder();
<span class="hljs-comment">/**
* 设置缓存
*/</span>
File cacheFile = <span class="hljs-keyword">new</span> File(ApplicationContext.context.getExternalCacheDir(), CACHE_NAME);
Cache cache = <span class="hljs-keyword">new</span> Cache(cacheFile, <span class="hljs-number">1024</span> * <span class="hljs-number">1024</span> * <span class="hljs-number">50</span>);
Interceptor cacheInterceptor = <span class="hljs-keyword">new</span> Interceptor() {
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> Response <span class="hljs-title">intercept</span><span class="hljs-params">(Chain chain)</span> <span class="hljs-keyword">throws</span> IOException </span>{
Request request = chain.request();
<span class="hljs-keyword">if</span> (!NetUtil.isNetworkConnected()) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
<span class="hljs-keyword">if</span> (!NetUtil.isNetworkConnected()) {
<span class="hljs-keyword">int</span> maxAge = <span class="hljs-number">0</span>;
<span class="hljs-comment">// 有网络时 设置缓存超时时间0个小时</span>
response.newBuilder()
.header(<span class="hljs-string">"Cache-Control"</span>, <span class="hljs-string">"public, max-age="</span> + maxAge)
.removeHeader(CACHE_NAME)<span class="hljs-comment">// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效</span>
.build();
} <span class="hljs-keyword">else</span> {
<span class="hljs-comment">// 无网络时,设置超时为4周</span>
<span class="hljs-keyword">int</span> maxStale = <span class="hljs-number">60</span> * <span class="hljs-number">60</span> * <span class="hljs-number">24</span> * <span class="hljs-number">28</span>;
response.newBuilder()
.header(<span class="hljs-string">"Cache-Control"</span>, <span class="hljs-string">"public, only-if-cached, max-stale="</span> + maxStale)
.removeHeader(CACHE_NAME)
.build();
}
<span class="hljs-keyword">return</span> response;
}
};
okHttpBuilder.cache(cache).addInterceptor(cacheInterceptor);
<span class="hljs-comment">/**
* 设置头信息
*/</span>
Interceptor headerInterceptor = <span class="hljs-keyword">new</span> Interceptor() {
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> Response <span class="hljs-title">intercept</span><span class="hljs-params">(Chain chain)</span> <span class="hljs-keyword">throws</span> IOException </span>{
Request originalRequest = chain.request();
Request.Builder requestBuilder = originalRequest.newBuilder()
.addHeader(<span class="hljs-string">"Accept-Encoding"</span>, <span class="hljs-string">"gzip"</span>)
.addHeader(<span class="hljs-string">"Accept"</span>, <span class="hljs-string">"application/json"</span>)
.addHeader(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json; charset=utf-8"</span>)
.method(originalRequest.method(), originalRequest.body());
requestBuilder.addHeader(<span class="hljs-string">"Authorization"</span>, <span class="hljs-string">"Bearer "</span> + BaseConstant.TOKEN);<span class="hljs-comment">//添加请求头信息,服务器进行token有效性验证</span>
Request request = requestBuilder.build();
<span class="hljs-keyword">return</span> chain.proceed(request);
}
};
okHttpBuilder.addInterceptor(headerInterceptor);
// if (BuildConfig.DEBUG) {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
public void log(String message) {
Logger.d(message);
}
});
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
<span class="hljs-comment">//设置 Debug Log 模式</span>
okHttpBuilder.addInterceptor(loggingInterceptor);
// }
/**
* 设置超时和重新连接
*/
okHttpBuilder.connectTimeout(DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS);
okHttpBuilder.readTimeout(DEFAULT_WRITE_TIMEOUT, TimeUnit.SECONDS);
okHttpBuilder.writeTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS);
//错误重连
okHttpBuilder.retryOnConnectionFailure(true);
retrofit = <span class="hljs-keyword">new</span> Retrofit.Builder()
.client(okHttpBuilder.build())
.addConverterFactory(GsonConverterFactory.create())<span class="hljs-comment">//json转换成JavaBean</span>
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(BASE_URL)
.build();
httpService = retrofit.create(HttpService.class);
}
<span class="hljs-comment">//在访问HttpMethods时创建单例</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SingletonHolder</span> </span>{
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> HttpMethods INSTANCE = <span class="hljs-keyword">new</span> HttpMethods();
}
<span class="hljs-comment">//获取单例</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> HttpMethods <span class="hljs-title">getInstance</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">return</span> SingletonHolder.INSTANCE;
}
<span class="hljs-comment">/**
* 获取retrofit
*/</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> Retrofit <span class="hljs-title">getRetrofit</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">return</span> retrofit;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">changeBaseUrl</span><span class="hljs-params">(String baseUrl)</span> </span>{
retrofit = <span class="hljs-keyword">new</span> Retrofit.Builder()
.client(okHttpBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(baseUrl)
.build();
httpService = retrofit.create(HttpService.class);
}
<span class="hljs-comment">/**
* 获取httpService
*/</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> HttpService <span class="hljs-title">getHttpService</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">return</span> httpService;
}
<span class="hljs-comment">/**
* 设置订阅 和 所在的线程环境
*/</span>
<span class="hljs-keyword">public</span> <T> <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">toSubscribe</span><span class="hljs-params">(Observable<T> o, DisposableObserver<T> s)</span> </span>{
o.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retry(RETRY_COUNT)<span class="hljs-comment">//请求失败重连次数</span>
.subscribe(s);
}
}
4.设置回调:
调用者自己对请求数据进行处理 成功时 通过result是否等于1分别回调onSuccees和onFault,默认处理了401错误转登录。
public class OnSuccessAndFaultSub extends DisposableObserver<ResponseBody> implements ProgressCancelListener {
/**
* 是否需要显示默认Loading
*/
private boolean showProgress = true;
private OnSuccessAndFaultListener mOnSuccessAndFaultListener;
<span class="hljs-keyword">private</span> Context context;
<span class="hljs-keyword">private</span> WaitProgressDialog progressDialog;
<span class="hljs-comment">/**
* <span class="hljs-doctag">@param</span> mOnSuccessAndFaultListener 成功回调监听
*/</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">OnSuccessAndFaultSub</span><span class="hljs-params">(OnSuccessAndFaultListener mOnSuccessAndFaultListener)</span> </span>{
<span class="hljs-keyword">this</span>.mOnSuccessAndFaultListener = mOnSuccessAndFaultListener;
}
<span class="hljs-comment">/**
* <span class="hljs-doctag">@param</span> mOnSuccessAndFaultListener 成功回调监听
* <span class="hljs-doctag">@param</span> context 上下文
*/</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">OnSuccessAndFaultSub</span><span class="hljs-params">(OnSuccessAndFaultListener mOnSuccessAndFaultListener, Context context)</span> </span>{
<span class="hljs-keyword">this</span>.mOnSuccessAndFaultListener = mOnSuccessAndFaultListener;
<span class="hljs-keyword">this</span>.context = context;
progressDialog = <span class="hljs-keyword">new</span> WaitProgressDialog(context, <span class="hljs-keyword">this</span>);
}
<span class="hljs-comment">/**
* <span class="hljs-doctag">@param</span> mOnSuccessAndFaultListener 成功回调监听
* <span class="hljs-doctag">@param</span> context 上下文
* <span class="hljs-doctag">@param</span> showProgress 是否需要显示默认Loading
*/</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">OnSuccessAndFaultSub</span><span class="hljs-params">(OnSuccessAndFaultListener mOnSuccessAndFaultListener, Context context, <span class="hljs-keyword">boolean</span> showProgress)</span> </span>{
<span class="hljs-keyword">this</span>.mOnSuccessAndFaultListener = mOnSuccessAndFaultListener;
<span class="hljs-keyword">this</span>.context = context;
progressDialog = <span class="hljs-keyword">new</span> WaitProgressDialog(context, <span class="hljs-keyword">this</span>);
<span class="hljs-keyword">this</span>.showProgress = showProgress;
}
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showProgressDialog</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">if</span> (showProgress && <span class="hljs-keyword">null</span> != progressDialog) {
progressDialog.show();
}
}
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">dismissProgressDialog</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">if</span> (showProgress && <span class="hljs-keyword">null</span> != progressDialog) {
progressDialog.dismiss();
}
}
<span class="hljs-comment">/**
* 订阅开始时调用
* 显示ProgressDialog
*/</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onStart</span><span class="hljs-params">()</span> </span>{
showProgressDialog();
}
<span class="hljs-comment">/**
* 完成,隐藏ProgressDialog
*/</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onComplete</span><span class="hljs-params">()</span> </span>{
dismissProgressDialog();
progressDialog = <span class="hljs-keyword">null</span>;
}
<span class="hljs-comment">/**
* 对错误进行统一处理
* 隐藏ProgressDialog
*/</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onError</span><span class="hljs-params">(Throwable e)</span> </span>{
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">if</span> (e <span class="hljs-keyword">instanceof</span> SocketTimeoutException) {<span class="hljs-comment">//请求超时</span>
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (e <span class="hljs-keyword">instanceof</span> ConnectException) {<span class="hljs-comment">//网络连接超时</span>
mOnSuccessAndFaultListener.onFault(<span class="hljs-string">"网络连接超时"</span>);
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (e <span class="hljs-keyword">instanceof</span> SSLHandshakeException) {<span class="hljs-comment">//安全证书异常</span>
mOnSuccessAndFaultListener.onFault(<span class="hljs-string">"安全证书异常"</span>);
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (e <span class="hljs-keyword">instanceof</span> HttpException) {<span class="hljs-comment">//请求的地址不存在</span>
<span class="hljs-keyword">int</span> code = ((HttpException) e).code();
<span class="hljs-keyword">if</span> (code == <span class="hljs-number">504</span>) {
mOnSuccessAndFaultListener.onFault(<span class="hljs-string">"网络异常,请检查您的网络状态"</span>);
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (code == <span class="hljs-number">404</span>) {
mOnSuccessAndFaultListener.onFault(<span class="hljs-string">"请求的地址不存在"</span>);
} <span class="hljs-keyword">else</span> {
mOnSuccessAndFaultListener.onFault(<span class="hljs-string">"请求失败"</span>);
}
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (e <span class="hljs-keyword">instanceof</span> UnknownHostException) {<span class="hljs-comment">//域名解析失败</span>
mOnSuccessAndFaultListener.onFault(<span class="hljs-string">"域名解析失败"</span>);
} <span class="hljs-keyword">else</span> {
mOnSuccessAndFaultListener.onFault(<span class="hljs-string">"error:"</span> + e.getMessage());
}
} <span class="hljs-keyword">catch</span> (Exception e2) {
e2.printStackTrace();
} <span class="hljs-keyword">finally</span> {
Log.e(<span class="hljs-string">"OnSuccessAndFaultSub"</span>, <span class="hljs-string">"error:"</span> + e.getMessage());
dismissProgressDialog();
progressDialog = <span class="hljs-keyword">null</span>;
}
}
<span class="hljs-comment">/**
* 当result等于1回调给调用者,否则自动显示错误信息,若错误信息为401跳转登录页面。
* ResponseBody body = response.body();//获取响应体
* InputStream inputStream = body.byteStream();//获取输入流
* byte[] bytes = body.bytes();//获取字节数组
* String str = body.string();//获取字符串数据
*/</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onNext</span><span class="hljs-params">(ResponseBody body)</span> </span>{
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">final</span> String result = CompressUtils.decompress(body.byteStream());
Log.e(<span class="hljs-string">"body"</span>, result);
JSONObject jsonObject = <span class="hljs-keyword">new</span> JSONObject(result);
<span class="hljs-keyword">int</span> resultCode = jsonObject.getInt(<span class="hljs-string">"ErrorCode"</span>);
<span class="hljs-keyword">if</span> (resultCode == <span class="hljs-number">1</span>) {
mOnSuccessAndFaultListener.onSuccess(result);
} <span class="hljs-keyword">else</span> {
String errorMsg = jsonObject.getString(<span class="hljs-string">"ErrorMessage"</span>);
mOnSuccessAndFaultListener.onFault(errorMsg);
Log.e(<span class="hljs-string">"OnSuccessAndFaultSub"</span>, <span class="hljs-string">"errorMsg: "</span> + errorMsg);
}
} <span class="hljs-keyword">catch</span> (Exception e) {
e.printStackTrace();
}
}
<span class="hljs-comment">/**
* 取消ProgressDialog的时候,取消对observable的订阅,同时也取消了http请求
*/</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCancelProgress</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.isDisposed()) {
<span class="hljs-keyword">this</span>.dispose();
}
}
}
*请求服务loading关闭监听
*/
public interface ProgressCancelListener {
void onCancelProgress();
}
5.请求的用法:
建议分类成不同的api,以便快速查找
api里面进行观察者和被观察者的订阅
private void getUserData() {
OnSuccessAndFaultListener l = new OnSuccessAndFaultListener() {
@Override
public void onSuccess(String result) {//成功回调
YXSPreference.setUserData(result);
userDataBean = GsonUtils.fromJson(result, UserDetailResponseBean.class);
fullData();
}
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFault</span><span class="hljs-params">(String errorMsg)</span> </span>{<span class="hljs-comment">//失败的回调</span>
SnackBarManager.showShortMsg(getActivity(), errorMsg);
}
};
UserApi.getUserAllDetails(<span class="hljs-keyword">new</span> OnSuccessAndFaultSub(l) , YXSPreference.getMemberId()
);
}
OnSuccessAndFaultSub 继承 Subscriber<ResponseBody>
public class UserApi {
/**
* 获取用户详细信息
*/
public static void getUserAllDetails(DisposableObserver<ResponseBody> subscriber, int memberId) {
GetUserAllDetailsRequestBean bean = new GetUserAllDetailsRequestBean();
bean.getData().setMemberId(memberId);
Observable observable = HttpMethods.getInstance().getHttpService().getUserAllDetails(bean); //在HttpServer中
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
}
以上就是RxJava2+Retrofit2+OkHttp3的具体使用,看不明白或者写的不对的咱们可以互相探讨,希望看了能帮助到大家,如需转载请注明地址,喜欢请关注一下感激不尽,我是猿里面比较会吃的,也会写点京城美食的相关文章~
Github地址:https://github.com/bigeyechou/NetWorkFrame
</div>
</div>