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;
}}}











 
    
评论