retrofit 和rxjava整理的几个点

文章地址 :https://gank.io/post/56e80c2c677659311bed9841

http://gank.io/post/560e15be2dca930e00da1083#toc_14

 

文章:https://www.jianshu.com/p/0d1fb9f08a34

 

添加公共参数

实际项目中,每个接口都有一些基本的相同的参数,我们称之为公共参数,比如: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);



作者:God丶Eye
链接:https://www.jianshu.com/p/0ad99e598dba
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

 

这个是retrofit的一个接口请求的步骤。

1.单纯的retrofit请求 

//进行网络请求
private void getMovie(){
    String baseUrl = "https://api.douban.com/v2/movie/";

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    MovieService movieService = retrofit.create(MovieService.class);
    Call<MovieEntity> call = movieService.getTopMovie(0, 10);
    call.enqueue(new Callback<MovieEntity>() {
        @Override
        public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
            resultTV.setText(response.body().toString());
        }

        @Override
        public void onFailure(Call<MovieEntity> call, Throwable t) {
            resultTV.setText(t.getMessage());
        }
    });
}

以上为没有经过封装的、原生态的Retrofit写网络请求的代码。 我们可以封装创建Retrofit和service部分的代码,然后Activity用创建一个Callback作为参数给Call,这样Activity中只关注请求的结果,而且Call有cancel方法可以取消一个请求,好像没Rxjava什么事了,我觉得可以写到这就下班了~

2.retrofit和rxjava之间的关系 

Retrofit本身对Rxjava提供了支持。

添加Retrofit对Rxjava的支持需要在Gradle文件中添加

compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'

然后在创建Retrofit的过程中添加如下代码:

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

这样一来我们定义的service返回值就不在是一个Call了,而是一个Observable

重新定义MovieService

public interface MovieService {
    @GET("top250")
    Observable<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);
}

3.  如何返回统一的数据 

按照我们之前的用法,使用Gson转型需要我们在创建subscriber对象是指定返回值类型,如果我们对不同的返回值进行封装的话,那可能就要有上百个Entity了,看着明明是很清晰的结构,却因为data的不确定性无奈了起来。

少年,不必烦恼,来来来~ 老衲赐你宝典葵花,老衲就是练了这个才出家。。。

我们可以创建一个HttpResult类

public class HttpResult<T> {
    private int resultCode;
    private String resultMessage;

    private T data;
}

如果data是一个User对象的话。那么在定义Service方法的返回值就可以写为

Observable<HttpResult<User>>

这样一来HttpResult就相当于一个包装类,将结果包装了起来,但是在使用的时候要给出一个明确的类型。

4.什么叫包装类

包装类即使把基本类型变成对象类型 

像ArrayList这样的集合是不能储存基本类型的只能储存对象 为了方便这些集合的使用所以才有了把基本类型包装成对象类型
ArrayList<Integer> al = new ArrayList<Integer>();
Integer i = 1;
al.add(i);
//直接把数字写进去也可以
al.add(2);
ArrayList<Integer> al = new ArrayList<Integer>();
Integer i = 1;
al.add(i);
//直接把数字写进去也可以
al.add(2);

包装类,把基本类型转换成对象 

泛型的参数不能是基本是基本数据类型(int 、char等)。

 

泛型是新的类型,可以指定多个类型参数,成为新的不同的类型

 

包装类和泛型  的区别   包装类把基本类型转换成对象, 泛型,可以是新的对象,例如UserEntity等。

5.

安卓6.0 之后 很多权限需要动态申请, 动态申请权限 ,

6. 统一处理错误信息 ,如何统一处理错误信息

我们在resultCode != 0的时候,抛出个自定义的ApiException。这样就会进入到subscriber的onError中,我们可以在onError中处理错误信息。

抛出自定义的异常 ,这样就会进入到 subscriber的onError中

当code!=0 或者 数据为空啊,等情况 抛出异常,然后在onError中处理异常, 然后设置当前的页面是哪一个, 是没网是空,还是加载失败。

 

@Override

public void onError(Throwable e) {

if (mMultipleStatusView.getViewStatus() != MultipleStatusView.STATUS_CONTENT) {

if (EmptyException.EMPTY_MSG.equals(e.getMessage())) {//在这里处理异常

mMultipleStatusView.showEmpty();

} else {

mMultipleStatusView.showError();

}

}

}

@Override

public void onNext(BaseEntity<RankMemberListEntity> rankListEntity) {

app.setServerTime(rankListEntity.server_time);

if (HttpConstant.REQUEST_SUCCESS_CODE == rankListEntity.code) {

if (rankListEntity.data.rankList == null || rankListEntity.data.rankList.size() == 0) {

throw new EmptyException();//抛出自定义的异常

}

} else {

RecyclerViewStateUtils.setFooterViewState(PaiHangActivity.this, mRecyclerView, Constant.REQUEST_COUNT, LoadingFooter.State.NetWorkError, mFooterClick);

throw new RequestException();//抛出自定义的异常

}

}

});

 

7.   先将 retrofit 和rxjava两者结合, 然后再封装请求的方法

两者结合的代码:

//进行网络请求

 

private void getMovie(){

String baseUrl = "https://api.douban.com/v2/movie/";

Retrofit retrofit = new Retrofit.Builder()

.baseUrl(baseUrl)

.addConverterFactory(GsonConverterFactory.create())

.addCallAdapterFactory(RxJavaCallAdapterFactory.create())

.build();

MovieService movieService = retrofit.create(MovieService.class);

movieService.getTopMovie(0, 10)

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe(new Subscriber<MovieEntity>() {

@Override

public void onCompleted() {

Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();

}

@Override

public void onError(Throwable e) {

resultTV.setText(e.getMessage());

}

@Override

public void onNext(MovieEntity movieEntity) {

resultTV.setText(movieEntity.toString());

}

});

}

 

下面是对 请求这边的一个封装 , (单例 )

问一下,单例模式怎么写 

淘头条中:

 

public static ApiService getInstance(Context mContext) {
    if (service == null) {
        synchronized (ApiService.class) {
            if (service == null) {
                service = new ApiService(mContext.getApplicationContext());
            }
        }
    }
    return service;
}

另外别的项目中:

//在访问HttpMethods时创建单例

private static class SingletonHolder{

private static final HttpMethods INSTANCE = new HttpMethods();

}

//获取单例

public static HttpMethods getInstance(){

return SingletonHolder.INSTANCE;

}

8.关于包装类返回数据

这样一来HttpResult就相当于一个包装类,将结果包装了起来,但是在使用的时候要给出一个明确的类型。

 

public class HttpResult<T> {

private int resultCode;

private String resultMessage;

private T data;

}

 

9.关于rxjava

 

与传统观察者模式不同, RxJava 的事件回调方法除了普通事件 onNext() (相当于 onClick() / onEvent())之外,还定义了两个特殊的事件:onCompleted() 和 onError()

  • onCompleted(): 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。
  • onError(): 事件队列异常。在事件处理过程中出异常时,onError() 会被触发,同时队列自动终止,不允许再有事件发出。
  • 在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个,并且是事件序列中的最后一个。需要注意的是,onCompleted() 和 onError() 二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。

 

onCompleted ()和onError() 两者 只有一个执行 , 并且是最后一个; 走onNext ()再走 onComplete()

10.rxjava订阅这里

Onserver也总会先被转换成一个 Subseriber再使用

RxJAVA中Observer/subscriber 接口的实现方式

 

Observer<String> observer = new Observer<String>() {

@Override

public void onNext(String s) {

Log.d(tag, "Item: " + s);

}

@Override

public void onCompleted() {

Log.d(tag, "Completed!");

}

@Override

public void onError(Throwable e) {

Log.d(tag, "Error!");

}

};

 

 

 

Subscribe (订阅)

创建了 Observable 和 Observer 之后,再用 subscribe() 方法将它们联结起来,整条链子就可以工作了。代码形式很简单:

observable.subscribe(observer);//

或者:

observable.subscribe(subscriber);

 

10.rxjava 的 异步  通过 scheduler (调度器)进行控制 

 

  • Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。

*  Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。

被观察者.subscribe(观察者) 这是一个观察者模式

 

observable.subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(观察者);

 

 

 

有了这几个 Scheduler ,就可以使用 subscribeOn() 和 observeOn() 两个方法来对线程进行控制了。 * subscribeOn(): 指定 subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程。或者叫做事件产生的线程。 * observeOn(): 指定 Subscriber 所运行在的线程。或者叫做事件消费的线程。

文字叙述总归难理解,上代码:

Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer number) {
            Log.d(tag, "number:" + number);
        }
    });

上面这段代码中,由于 subscribeOn(Schedulers.io()) 的指定,被创建的事件的内容 1234 将会在 IO 线程发出;而由于 observeOn(AndroidScheculers.mainThread()) 的指定,因此 subscriber 数字的打印将发生在主线程 。事实上,这种在 subscribe() 之前写上两句 subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式非常常见,它适用于多数的 『后台线程取数据,主线程显示』的程序策略。

subscribeOn是 发生在哪个线程, io线程的话,便于读取数据,且线程数量无上限

observeOn 是回调的方法在哪个线程处理,消费 主线程 

Schedulers)调度器的几种方法:

 

  • Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler
  • Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。
  • Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
  • Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
  • 另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。

 

这一下就知道了 , btn是被观察者 , onClickListener 是 观察者  setOnclicklistener 是订阅 

一年至少要看两三百本书 , 那么 ,平均 一天多点就是一本书 

观察者要放在主线程 , 

如果被点击了,去告知 ; 小偷拿了东西告诉警察  

 

这个接口的调度,

 就可以使用 subscribeOn() 和 observeOn() 两个方法来对线程进行控制了。 

subscribeOn(): 指定 subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程。或者叫做事件产生的线程。在子线程中,订阅发生在哪个线程 

 * observeOn(): 指定 Subscriber 所运行在的线程。或者叫做事件消费的线程。 就是onCompleted(),onNext()这几个方法

observable.subscribeOn(Schedulers.io()) 订阅,被激活 发生在哪个线程,子线程下载数据,查阅数据库和网络数据。

.observeOn(AndroidSchedulers.mainThread())这句话说明,三个方法里面(,onNext()等)的内容是放在主线程的

.subscribe()

 

文字叙述总归难理解,上代码:

Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer number) {
            Log.d(tag, "number:" + number);
        }
    });

上面这段代码中,由于 subscribeOn(Schedulers.io()) 的指定,被创建的事件的内容 1234 将会在 IO 线程发出;而由于 observeOn(AndroidScheculers.mainThread()) 的指定,因此 subscriber 数字的打印将发生在主线程 。事实上,这种在 subscribe() 之前写上两句 subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式非常常见,它适用于多数的 『后台线程取数据,主线程显示』的程序策略。

 

在subscribe( )之前写上两句 subscribeOn(Scheduler.io( ))和 onserveOn(AndroidSchedulers.mainThread)的这种方式非常常见,它适用于多数的 {后台线程取数据,主线程显示} 的程序策略。

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值