欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

【Android】Retrofit+RxJava+OkHttp的基础、封装和项目中的使用

程序员文章站 2022-05-13 23:41:30
【android】retrofit+rxjava+okhttp的基础、封装和项目中的使用。近些年很火的retrofit+rxjava+okhttp网络请求框架,功能强大,结构合理,使用简单方便。后面...

android】retrofit+rxjava+okhttp的基础、封装和项目中的使用。近些年很火的retrofit+rxjava+okhttp网络请求框架,功能强大,结构合理,使用简单方便。后面还会给大家发自己整理过的retrofit和rxjava、rxandroid和rxbus。希望大家点一下关注,让我这个懒癌患者有动力继续写下去!
本篇分三个部分:基础篇、封装篇和自己项目使用篇,项目是自己公司的app提取的,文章偏长可以分三部分一点点看,当初看了很多优秀的文章然后自己在整理写在印象笔记中,可惜当初没记下借鉴过的文章地址,十分抱歉。
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.1.0'//retrofit
compile 'com.google.code.gson:gson:2.6.2'//gson 库
//下面两个是rxjava 和 rxandroid
compile 'io.reactivex:rxjava:1.1.0'
compile 'io.reactivex:rxandroid:1.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'//转换器,请求结果转换成model
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.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 gettop250 (@query("start") int start , @query("count") int count);

@formurlencoded
@post("top250")
call 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 call = movieservice.gettop250(0,20);
 //进行网络请求
call.enqueue(new callback() {
       @override
       public void onresponse(call call, response response) {
            mmovieadapter.setmovies(response.body().subjects);     
            mmovieadapter.notifydatasetchanged();
       }
      @override
      public void onfailure(call call, throwable t) {
         t.printstacktrace();
      }
});

同步方式请求: 返回一个response

response response = call.execute();
二,配合rxjava 使用:
更改定义的接口,返回值不再是一个 call ,而是返回的一个 observble:
public interface movieservice {
//获取豆瓣top250 榜单
@get("top250")
observable gettop250(@query("start") int start, @query("count")int count);
}

2.创建 retrofit 的时候添加如下代码:

addcalladapterfactory(rxjavacalladapterfactory.create())

3.添加转换器converter(将 json 转为 javabean):

addconverterfactory(gsonconverterfactory.create())

举实际项目中使用的例子:

retrofit = new retrofit.builder()
        .client(okhttpbuilder.build())
        .addconverterfactory(gsonconverterfactory.create())
        .addcalladapterfactory(rxjavacalladapterfactory.create())
        .baseurl(base_url)
        .build();

4.activity 或者 fragment 中传入 subscriber 建立订阅关系:

subscription subscription = movieservice.gettop250(0,20)
.subscribeon(schedulers.io())
.observeon(androidschedulers.mainthread())
.subscribe(new subscriber() {
@override
public void oncompleted() {

 }
@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(rxjavacalladapterfactory.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(rxjavacalladapterfactory.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(rxjavacalladapterfactory.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    
    * @return 
    */ 
  public  t create(class service){
       return mretrofit.create(service);   
}

}

接口实例service都可以用这个来生成,代码如下:

mmovieservice = retrofitservicemanager.getinstance().create(movieservice.class);
二,创建接口,通过第一步获取实例

有了可以获取接口实例的方法,然后创建一个接口,代码如下:

public interface movieservice{ 
  //获取豆瓣top250 榜单 
  @get("top250")   
  observable gettop250(@query("start") int start, @query("count") int count); 

  @formurlencoded   
  @post("/x3/weather") 
  call 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> getmovie(int start, int count){ 
      return observe(mmovieservice.gettop250(start , count)).map(new func1>() { 
        @override
        public list call(moviesubject moviesubject) { 
        return moviesubject.subjects;   
      } 
    });
  } 

public observable getweatherlist(string cityid,string key){   
      return observe(mmovieservice.getweather(cityid , key)).map(new func1() {   
       @override     
       public string call(string s) {
          //可以处理对应的逻辑后在返回
            return s;   
      }
    });
}

public interface movieservice{
    //获取豆瓣top250 榜单 
    @get("top250")     
    observable gettop250(@query("start") int start, @query("count")int count); 

    @formurlencoded 
    @post("/x3/weather")   
    call 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  
  * @return   
  */ 
protected   observable observe(observable 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>() { 
    @override 
    public void call(list movies) { 
        mmovieadapter.setmovies(movies);       
        mmovieadapter.notifydatasetchanged();     
        }
  }, new action1() {   
    @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 { 
  public int status; 
  public string message;   
  public t data;   
  public boolean issuccess(){ 
    return status == 200; 
  }
}

有了统一的格式数据后,我们需要 剥离出data{ }返回给 上层调用者,创建一个 payload 类,代码如下:

/**
 * 剥离 最终数据
 */
public class payload implements func1{   
@override
  public t call(baseresponse tbaseresponse) {//获取数据失败时,包装一个fault 抛给上层处理错误
        if(!tbaseresponse.issuccess()){
          throw new fault(tbaseresponse.status,tbaseresponse.message); 
      }   
    return tbaseresponse.data; 
  }
}

payload 继承自 func1,接收一个baseresponse , 就是接口返回的 json 数据结构,返回的是 t,就是data{ },判断是否请求成功,请求成功 返回data,请求失败 包装成一个 fault 返回给上层统一处理错误。
在loader类里面获取结果后,通过map 操作符剥离数据。代码如下:

public observable> getmovie(int start, int count){
  return observe(mmovieservice.gettop250(start,count))       
    .map(new payload>());
}

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 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 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.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'io.reactivex:rxandroid:1.2.0'
compile 'io.reactivex:rxjava:1.1.5'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
compile 'com.squareup.okhttp3:logging-interceptor:3.5.0'

2.创建一个httpservice接口:

public interface httpservice {
/**
 * 获取用户详细资料
 */
@post("api/xxx/getuseralldetails")
observable getuseralldetails(@body getuseralldetailsrequestbean bean);

/**
 * @param apkurl 下载地址
 */
@get()
@streaming
call downloadnewapk(@url string apkurl);

/**
 * 获取推广大使分享图片
 */
@get("api/xxx/invitedimage")
observable getinvitedimage(@querymap map 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(rxjavacalladapterfactory.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(rxjavacalladapterfactory.create())
                .baseurl(baseurl)
                .build();
        httpservice = retrofit.create(httpservice.class);
    }

    /**
     * 获取httpservice
     */
    public httpservice gethttpservice() {
        return httpservice;
    }

     /**
     * 设置订阅 和 所在的线程环境
     */
    public  void tosubscribe(observable o, subscriber 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 subscriber 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 oncompleted() {
        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跳转登录页面。
      */
    @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.isunsubscribed()) {
            this.unsubscribe();
        }
    }
}
 *请求服务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

public class userapi {
    /**
     * 获取用户详细信息
     */
    public static void getuseralldetails(subscriber subscriber, int memberid) {
        getuseralldetailsrequestbean bean = new getuseralldetailsrequestbean();
        bean.getdata().setmemberid(memberid);
        observable observable = httpmethods.getinstance().gethttpservice().getuseralldetails(bean); //在httpserver中
        httpmethods.getinstance().tosubscribe(observable, subscriber);
    }
}