Android版&Kotlin版RxJava2+Retrofit2+OkHttp3的基础、封装和项目中的使用

前言:

近些年很火的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
持续迭代中...,更新内容是升级版本替换成RxJava2,修改了一些语法。
Github地址:java版本:https://github.com/bigeyechou/NetWorkFrame
Github地址:kotlin的版本:https://github.com/bigeyechou/AndroidKotlin

简单介绍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);

@FormUrlEncoded
@POST("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 使用:
  1. 更改定义的接口,返回值不再是一个 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() {

 }
@Override
public void onError(Throwable e) {

}
@Override
 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);//读操作超时时间 
     
     // 添加公共参数拦截器       
     HttpCommonInterceptor commonInterceptor = new HttpCommonInterceptor.Builder()
               .addHeaderParams("paltform","android")
               .addHeaderParams("userToken","1234343434dfdfd3434")
               .addHeaderParams("userId","123445")     
               .build();       
     builder.addInterceptor(commonInterceptor);  
 
     // 创建Retrofit       
     mRetrofit = new 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();
    }

    /**
     * 获取RetrofitServiceManager
     * @return
     */   
 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); 

  @FormUrlEncoded   
  @POST("/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>() {   
       @Override     
       public String call(String s) {
          //可以处理对应的逻辑后在返回
            return s;   
      }
    });
}

public interface MovieService{
    //获取豆瓣Top250 榜单 
    @GET("top250")     
    Observable<MovieSubject> getTop250(@Query("start") int start, @Query("count")int count); 

    @FormUrlEncoded 
    @POST("/x3/weather")   
    Call<String> getWeather(@Field("cityId") String cityId, @Field("key") String key); 
}
}
创建一个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());*/
 
      // 新的请求 
      Request.Builder requestBuilder =  oldRequest.newBuilder();
      requestBuilder.method(oldRequest.method(), oldRequest.body());

      //添加公共参数,添加到header中       
     if(mHeaderParamsMap.size() > 0){     
          for(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 下载地址
 */
@GET()
@Streaming
Call<ResponseBody> downloadNewApk(@Url String apkUrl);

/**
 * 获取推广大使分享图片
 */
@GET("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;

    //构造方法私有
    private HttpMethods() {
        //手动创建一个OkHttpClient并设置超时时间
        okHttpBuilder = new OkHttpClient.Builder();

        /**
         * 设置缓存
         */
        File cacheFile = new File(ApplicationContext.context.getExternalCacheDir(), CACHE_NAME);
        Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
        Interceptor cacheInterceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                if (!NetUtil.isNetworkConnected()) {
                    request = request.newBuilder()
                            .cacheControl(CacheControl.FORCE_CACHE)
                            .build();
                }
                Response response = chain.proceed(request);
                if (!NetUtil.isNetworkConnected()) {
                    int maxAge = 0;
                    // 有网络时 设置缓存超时时间0个小时
                    response.newBuilder()
                            .header("Cache-Control", "public, max-age=" + maxAge)
                            .removeHeader(CACHE_NAME)// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效
                            .build();
                } else {
                    // 无网络时,设置超时为4周
                    int maxStale = 60 * 60 * 24 * 28;
                    response.newBuilder()
                            .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                            .removeHeader(CACHE_NAME)
                            .build();
                }
                return response;
            }
        };
        okHttpBuilder.cache(cache).addInterceptor(cacheInterceptor);


        /**
         * 设置头信息
         */
        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);


//        if (BuildConfig.DEBUG) {
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                Logger.d(message);
            }


        });
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        //设置 Debug Log 模式
        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 = new Retrofit.Builder()
                .client(okHttpBuilder.build())
                .addConverterFactory(GsonConverterFactory.create())//json转换成JavaBean
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(BASE_URL)
                .build();
        httpService = retrofit.create(HttpService.class);
    }

    //在访问HttpMethods时创建单例
    private static class SingletonHolder {
        private static final HttpMethods INSTANCE = new HttpMethods();

    }

    //获取单例
    public static HttpMethods getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /**
     * 获取retrofit
     */
    public Retrofit getRetrofit() {
        return retrofit;
    }

    public void changeBaseUrl(String baseUrl) {
        retrofit = new Retrofit.Builder()
                .client(okHttpBuilder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(baseUrl)
                .build();
        httpService = retrofit.create(HttpService.class);
    }

    /**
     * 获取httpService
     */
    public HttpService getHttpService() {
        return httpService;
    }

     /**
     * 设置订阅 和 所在的线程环境
     */
    public <T> void toSubscribe(Observable<T> o, DisposableObserver<T> s) {

        o.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .retry(RETRY_COUNT)//请求失败重连次数
                .subscribe(s);

    }
}

4.设置回调:
调用者自己对请求数据进行处理 成功时 通过result是否等于1分别回调onSuccees和onFault,默认处理了401错误转登录。

public class OnSuccessAndFaultSub extends DisposableObserver<ResponseBody> implements ProgressCancelListener {
    /**
     * 是否需要显示默认Loading
     */
    private boolean showProgress = true;
    private OnSuccessAndFaultListener mOnSuccessAndFaultListener;

    private Context context;
    private WaitProgressDialog progressDialog;

    /**
     * @param mOnSuccessAndFaultListener 成功回调监听
     */
    public OnSuccessAndFaultSub(OnSuccessAndFaultListener mOnSuccessAndFaultListener) {
        this.mOnSuccessAndFaultListener = mOnSuccessAndFaultListener;
    }

    /**
     * @param mOnSuccessAndFaultListener 成功回调监听
      * @param context                    上下文
      */
    public OnSuccessAndFaultSub(OnSuccessAndFaultListener mOnSuccessAndFaultListener, Context context) {
        this.mOnSuccessAndFaultListener = mOnSuccessAndFaultListener;
        this.context = context;
        progressDialog = new WaitProgressDialog(context, this);
    }

    /**
     * @param mOnSuccessAndFaultListener 成功回调监听
      * @param context                    上下文
      * @param showProgress               是否需要显示默认Loading
     */
    public OnSuccessAndFaultSub(OnSuccessAndFaultListener mOnSuccessAndFaultListener, Context context, boolean showProgress) {
        this.mOnSuccessAndFaultListener = mOnSuccessAndFaultListener;
        this.context = context;
        progressDialog = new WaitProgressDialog(context, this);
        this.showProgress = showProgress;
    }

    private void showProgressDialog() {
        if (showProgress && null != progressDialog) {
            progressDialog.show();
        }
    }

    private void dismissProgressDialog() {
        if (showProgress && null != progressDialog) {
            progressDialog.dismiss();
        }
    }

    /**
     * 订阅开始时调用
      * 显示ProgressDialog
     */
    @Override
    public void onStart() {
        showProgressDialog();
    }

    /**
     * 完成,隐藏ProgressDialog
     */
    @Override
    public void onComplete() {
        dismissProgressDialog();
        progressDialog = null;
    }

    /**
     * 对错误进行统一处理
      * 隐藏ProgressDialog
     */
    @Override
    public void onError(Throwable e) {
        try {

            if (e instanceof SocketTimeoutException) {//请求超时
            } else if (e instanceof ConnectException) {//网络连接超时
                mOnSuccessAndFaultListener.onFault("网络连接超时");
            } else if (e instanceof SSLHandshakeException) {//安全证书异常
                mOnSuccessAndFaultListener.onFault("安全证书异常");
            } else if (e instanceof HttpException) {//请求的地址不存在
                int code = ((HttpException) e).code();
                if (code == 504) {
                    mOnSuccessAndFaultListener.onFault("网络异常,请检查您的网络状态");
                } else if (code == 404) {
                    mOnSuccessAndFaultListener.onFault("请求的地址不存在");
                } else {
                    mOnSuccessAndFaultListener.onFault("请求失败");
                }
            } else if (e instanceof UnknownHostException) {//域名解析失败
                mOnSuccessAndFaultListener.onFault("域名解析失败");
            } else {
                mOnSuccessAndFaultListener.onFault("error:" + e.getMessage());
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        } finally {
            Log.e("OnSuccessAndFaultSub", "error:" + e.getMessage());
            dismissProgressDialog();
            progressDialog = null;

        }

    }

    /**
     * 当result等于1回调给调用者,否则自动显示错误信息,若错误信息为401跳转登录页面。
     * ResponseBody  body = response.body();//获取响应体
     * InputStream inputStream = body.byteStream();//获取输入流
     * byte[] bytes = body.bytes();//获取字节数组
     * String str = body.string();//获取字符串数据
     */
    @Override
    public void onNext(ResponseBody body) {
        try {
            final String result = CompressUtils.decompress(body.byteStream());
            Log.e("body", result);
            JSONObject jsonObject = new JSONObject(result);
            int resultCode = jsonObject.getInt("ErrorCode");
            if (resultCode == 1) {
                mOnSuccessAndFaultListener.onSuccess(result);
            } else {
                String errorMsg = jsonObject.getString("ErrorMessage");
                mOnSuccessAndFaultListener.onFault(errorMsg);
                Log.e("OnSuccessAndFaultSub", "errorMsg: " + errorMsg);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 取消ProgressDialog的时候,取消对observable的订阅,同时也取消了http请求
      */
    @Override
    public void onCancelProgress() {
        if (!this.isDisposed()) {
            this.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();
        }

        @Override
        public void onFault(String errorMsg) {//失败的回调
            SnackBarManager.showShortMsg(getActivity(), errorMsg);
        }
    };

    UserApi.getUserAllDetails(new 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
转换为kotlin的版本:https://github.com/bigeyechou/AndroidKotlin

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容