写点什么

Retrofit-+-RxJava-+-OkHttp- 让网络请求变的简单 - 封装篇

用户头像
Android架构
关注
发布于: 2021 年 11 月 05 日

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


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


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;


}}}

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Retrofit-+-RxJava-+-OkHttp-让网络请求变的简单-封装篇