Retrofit-+-RxJava-+-OkHttp- 让网络请求变的简单 - 封装篇
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,构造方法中生成了 mMovieService,而 Service 中可以定义和业务相关的多个 api,比如:例子中的 MovieService 中,可以定义和电影相关的多个 api,获取电影列表、获取电影详情、搜索电影等 api,就不用定义多个接口了。
上面的代码中,MovieLoader 是从 ObjectLoader 中继承下来的,ObjectLoader 提取了一些公共的操作。代码如下:
/***
将一些重复的操作提出来,放到父类以免 Loader 里每个接口都有重复代码
Created by zhou
wei on 16/11/10.*/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());
}
});}
以上就完成请求过程的封装,现在添加一个新的请求,只需要添加一个业务 Loader 类,然后通过 Loader 调用方法获取结果就行了,是不是方便了很多?但是在实际项目中这样是不够的,还能做进一步简化。
五,统一处理结果和错误
1,统一处理请求结果
现实项目中,所有接口的返回结果都是同一格式,如:
{"status": 200,"message": "成功","data": {}}
我们在请求 api 接口的时候,只关心我们想要的数据,也就上面的 data,其他的东西我们不太关心,请求失败的时候可以根据 status 判断进行错误处理,所以我们需要包装一下。首先需要根据服务端定义的 JSON 结构创建一个 BaseResponse 类,代码如下:
/***
网络请求结果 基类
Created by zhouwei on 16/11/10.*/public class BaseResponse<T> {
public int status;
public String message;
public T data;
public boolean isSuccess(){
return status == 200;
}}
有了统一的格式数据后,我们需要剥离出 data 返回给上层调用者,创建一个 PayLoad 类,代码如下:
/***
剥离 最终数据
Created by zhouwei on 16/11/10.*/public class PayLoad<T> implements Func1<BaseResponse<T>,T>{
@Overridepublic 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 等等,我们不必要,每个接口都去写,这样就太麻烦了,因此我们可以写一个拦截器,在拦截器里面拦截请求,为每个请求都添加相同的公共参数。拦截器代码如下:
/**
拦截器
向请求头里添加公共参数
Created by zhouwei on 16/11/10./public class HttpCommonInterceptor implements Interceptor {private Map<String,String> mHeaderParamsMap = new HashMap<>();public HttpCommonInterceptor() {}@Overridepublic 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;
}}}
评论