Retrofit+RxJava 完美封装

本来在项目中是使用了Volley 然后封装 封装了一个HttpUtils,
但是由于项目中要引入RxJava,所以就顺便替换一下Volley,使用Retrofit+RxJava。

Volley框架,我这里就 不过多介绍了,大家如果想学习的会可以自己去了解下。
http://blog.csdn.net/ysh06201418/article/details/46443235

首先大家可以参考下其他的Retrofit+RxJava的使用方法。
http://blog.csdn.net/byxyrq/article/details/52672202

如果大家对RxJava还不大了解的话,大家可以看下这篇文章。
http://gank.io/post/560e15be2dca930e00da1083

下面我介绍下我是如何封装Retrofit+RxJava的。
这是我公司的后台返回的json数据格式:

{  
    data:返回的数据,  
    errorCode:200,  
    moreInfo:"错误详情"  
}  

其中'data'中返回的才是我们真正需要的内容,而‘errorCode’不为200,则是后台出错,具体错误信息放在‘moreInfo’中。
而如果直接使用Retrofit+RxJava。如下:

/** 
 * 登录 
 */  
@POST  
@FormUrlEncoded  
Observable login(@Url String url , @FieldMap Mapparam); 

如果直接使用该接口,那么需要后台直接返回‘UserVO’的json数据。
但是依照前面所说,后台所有的返回数据都是依照

{  
    data:返回的数据,  
    errorCode:200,  
    moreInfo:"错误详情"  
} 

这种格式的数据返回。所以请求这个接口后,其实真正返回的数据应该是如下这样:

{  
    data:{UserVO对象},  
    errorCode:200,  
    moreInfo:"错误详情"  
} 

如上只是一个例子而已,其实所有接口,都是依照这种格式回传,所以在Retrofit+RxJava框架对返回的数据

进行处理之前,需要自己提前处理一下,先判断'errorCode'是否为200,如果为200就是正常请求数据返回,然后

获取到data的数据返回给Retrofit+RxJava框架进行处理。如果不为200,则为错误,根据错误的类型进行相应的处理。

如下:

/** 
    * 统一处理原始数据 
    * 
    * @param originalResponse 
    */  
   private static Response dealResponseData(Response originalResponse) {  
       String jsonString = null;  
       try {  
           BufferedSource bufferedSource = originalResponse.body().source();  
           jsonString = bufferedSource.readString(Charset.forName("utf-8"));  
       } catch (Exception e) {  
           e.printStackTrace();  
       }  
       if (!jsonString.trim().startsWith("{") && !jsonString.trim().startsWith("[")) {  
           return onSuccess(originalResponse, jsonString);  
       }  
       ResponseMessageBean msgBean = ResponseMessageBean.analyseReponse(jsonString);  
       if (msgBean == null) return onSuccess(originalResponse, msgBean.data.toString());  
       if (msgBean != null && (msgBean.errorCode == 200)) {  
           showError = true;  
           if (msgBean.data != null) {  
               return onSuccess(originalResponse, msgBean.data.toString());  
           } else {  
               return originalResponse.newBuilder().body(null).build();  
           }  
       } else {  
           onFailed(msgBean);  
           throw new RuntimeException(msgBean.moreInfo.toString());  
       }  
   }  

请求之后返回一个Response对象,预先处理完成之后返回另一新的Response对象,这样就可以实现刚才的目的了。
ResponseMessageBean其实就是最外面的对象。
onSuccess方法中,其实主要对处理后的数据重新组装成一个新的Response对象

private static Response onSuccess(Response originalResponse, String content) {  
        return originalResponse.newBuilder().  
                body(ResponseBody.create(null, content)).  
                build();  
    } 

方法虽然简单,但是这里要注意一点,不能新建一个新的Response返回,因为你Response里面其实是有多数据的,你就使用原来的Response,
然后把body里面的内容替换下就好了。
其实这里还有一个onFailed方法,主要是后台请求报错了,没有返回200,就根据你自己后台定义的值来判断具体错误,然后具体处理,这里
我就不再具体描述了。

前面描述的是data返回值是一个对象,其实是一个数组也是一样的,只要你在泛型里面写的是List那么就会返回一个List对象,如下:

@POST  
   @FormUrlEncoded  
   Observable> userList(@Url String url , @FieldMap Mapparam);  

这样处理的数据其实是这种格式的

{  
    data:[{},{}],  
    errorCode:200,  
    moreInfo:"错误详情"  
} 

对了,我这里一直没有讲为什么Retrofit+RxJava会对返回的对象进行自动转换,因为我前面已经放了几篇文章,希望大家能先阅读了

一些基础的知识后,再来看这篇文章的具体封装,可能对你的帮助会更大一点。

Retrofit在初始化:

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

addConverterFactory其实是为了对返回内容的提供一个转换器。
这里官方实现了很多种转换器,如下

Gson: com.squareup.retrofit:converter-gson
Jackson: com.squareup.retrofit:converter-jackson
Moshi: com.squareup.retrofit:converter-moshi
Protobuf: com.squareup.retrofit:converter-protobuf
Wire: com.squareup.retrofit:converter-wire
Simple XML: com.squareup.retrofit:converter-simplexml
一共有这么几种,大家可以根据自己的返回格式和喜好,选择对应的转换器,我这里选择了Gson转换器。记得选择转换器,要引入对应的依赖,这里我就不再过多赘述了。

我这里为什么要讲这个转换器呢?因为在项目的的过程中,我发现了有这样的一个需求,就是返回值中的data不是对象,也不是数组,
如下:

{  
    data:"你好",  
    errorCode:200,  
    moreInfo:"错误详情"  
}  

或者是其他‘boolean’,‘int’等基础类型。就会出错。所以我这里重新对gson转换器做了封装,如下

public class TWGsonResponseBodyConverter implements Converter {  
  
    private final Gson gson;  
    private final TypeAdapter adapter;  
    private final TypeToken typeToken;  
  
    TWGsonResponseBodyConverter(Gson gson, TypeAdapter adapter, TypeToken typeToken) {  
        this.gson = gson;  
        this.adapter = adapter;  
        this.typeToken = typeToken;  
    }  
  
    @Override  
    public T convert(ResponseBody value) throws IOException {  
        Object obj = checkBasicType(value);  
        if (obj != null) return (T) obj;  
        JsonReader jsonReader = gson.newJsonReader(value.charStream());  
        try {  
            return adapter.read(jsonReader);  
        } finally {  
            value.close();  
        }  
    }  
  
    /** 
     * 如果是基本类型就转化后,返回 
     */  
    private Object checkBasicType(ResponseBody value) throws IOException {  
        String typeName = typeToken.getRawType().getSimpleName();  
        if ("String".equals(typeName)) {  
            return value.string();  
        } else if ("Boolean".equals(typeName)) {  
            return Boolean.parseBoolean(value.string());  
        } else if ("Integer".equals(typeName)) {  
            return Integer.parseInt(value.string());  
        }  
        return null;  
    }  
}  

在方法中判断是否为基础类型,如果为基础类型,或者String 就通过处理后,直接返回,如果不是,则还是通过原来的转换器转换。
这样子就可以适用所有情况了。
在我的项目中,有一个场景,就是需要在请求时,自定义请求头,虽然Retrofit有@Head,但是由于每次请求都需要设置,还是直接封装
在里面比较好,代码如下:

private static Request.Builder createRequestHeader(Request.Builder builder) {  
        builder.header("Content-Type",  
                "application/x-www-form-urlencoded");  
        builder.header("User-Agent", getUserAgent());  
        return builder;  
    }  

其实就是创建一个新的Request返回而已。
然后项目中又说要使用https来访问,所以我又加了下面的代码来支持:

if (mOkHttpClient == null) {  
                    try {  
                        X509TrustManager xtm = new X509TrustManager() {  
                            @Override  
                            public void checkClientTrusted(X509Certificate[] chain, String authType) {  
                            }  
  
                            @Override  
                            public void checkServerTrusted(X509Certificate[] chain, String authType) {  
                            }  
  
                            @Override  
                            public X509Certificate[] getAcceptedIssuers() {  
                                X509Certificate[] x509Certificates = new X509Certificate[0];  
                                return x509Certificates;  
                            }  
                        };  
  
                        SSLContext sslContext = null;  
                        try {  
                            sslContext = SSLContext.getInstance("SSL");  
  
                            sslContext.init(null, new TrustManager[]{xtm}, new SecureRandom());  
  
                        } catch (NoSuchAlgorithmException e) {  
                            e.printStackTrace();  
                        } catch (KeyManagementException e) {  
                            e.printStackTrace();  
                        }  
                        HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {  
                            @Override  
                            public boolean verify(String hostname, SSLSession session) {  
                                return true;  
                            }  
                        };  
  
                        // 指定缓存路径,缓存大小100Mb  
                        Cache cache = new Cache(new File(mContext.getCacheDir(), "HttpCache"), 1024 * 1024 * 100);  
                        mOkHttpClient = new OkHttpClient.Builder().  
                                addInterceptor(mRewriteCacheControlInterceptor).  
                                retryOnConnectionFailure(false).  
                                connectTimeout(30, TimeUnit.SECONDS).  
                                sslSocketFactory(sslContext.getSocketFactory()).  
                                hostnameVerifier(DO_NOT_VERIFY).  
                                cache(cache).  
                                build();  
                    } catch (Exception e) {  
                        e.printStackTrace();  
                    }  
                }  
            }  

并且还指定了缓存还有超时时间,重试次数,等等。

以上情况其实已经适用我当前项目的所以场景了。

下面是附上所有代码:

public class RetrofitHelper {  
    private static ServerApi api;  
    private static OkHttpClient mOkHttpClient;  
    private static Context mContext;  
    private static boolean showError = true;  
  
    /** 
     * 启动后初始化 
     */  
    public static void init(Context context) {  
        mContext = context;  
        initOkHttpClient();  
        Retrofit retrofit = new Retrofit.Builder().baseUrl(UrlConstant.BASEURL).  
                addConverterFactory(GsonConverterFactory.create()).  
                addCallAdapterFactory(RxJavaCallAdapterFactory.create()).  
                client(mOkHttpClient).  
                build();  
        api = retrofit.create(ServerApi.class);  
    }  
  
    /** 
     * 重置baseUrl 
     */  
    public static void resetBaseUrl() {  
        Retrofit retrofit = new Retrofit.Builder().baseUrl(UrlConstant.BASEURL).  
                addConverterFactory(TWGsonConverterFactory.create()).  
                addCallAdapterFactory(RxJavaCallAdapterFactory.create()).  
                client(mOkHttpClient).  
                build();  
        api = retrofit.create(ServerApi.class);  
    }  
  
  
    public static ServerApi getApi() {  
        return api;  
    }  
  
    /** 
     * 统一处理原始数据 
     * 
     * @param originalResponse 
     */  
    private static Response dealResponseData(Response originalResponse) {  
        String jsonString = null;  
        try {  
            BufferedSource bufferedSource = originalResponse.body().source();  
            jsonString = bufferedSource.readString(Charset.forName("utf-8"));  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        if (!jsonString.trim().startsWith("{") && !jsonString.trim().startsWith("[")) {  
            return onSuccess(originalResponse, jsonString);  
        }  
        ResponseMessageBean msgBean = ResponseMessageBean.analyseReponse(jsonString);  
        if (msgBean == null) return onSuccess(originalResponse, msgBean.data.toString());  
        if (msgBean != null && (msgBean.errorCode == 200)) {  
            showError = true;  
            if (msgBean.data != null) {  
                return onSuccess(originalResponse, msgBean.data.toString());  
            } else {  
                return originalResponse.newBuilder().body(null).build();  
            }  
        } else {  
            onFailed(msgBean);  
            throw new RuntimeException(msgBean.moreInfo.toString());  
        }  
    }  
  
    /** 
     * 初始化okHttp 
     */  
    private static void initOkHttpClient() {  
        if (mOkHttpClient == null) {  
            synchronized (RetrofitHelper.class) {  
                Interceptor mRewriteCacheControlInterceptor = new Interceptor() {  
                    @Override  
                    public Response intercept(Chain chain) throws IOException {  
                        Request request = chain.request();  
                        if (!NetworkUtils.isNetworkConnected(mContext)) {  
                            request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();  
                        }  
                        /** 
                         * 统一设置请求头 
                         */  
                        Request newRequest = createRequestHeader(request.newBuilder()).build();  
                        Response originalResponse = chain.proceed(newRequest);  
                        //如果是重定向,那么就执行重定向后返回数据。  
                        if (originalResponse.isRedirect()) {  
                            Request redirectRequest = request.newBuilder().url(originalResponse.header("location")).build();  
                            originalResponse = chain.proceed(redirectRequest);  
                        }  
                        originalResponse = dealResponseData(originalResponse);  
                        return originalResponse;  
                    }  
                };  
  
                if (mOkHttpClient == null) {  
                    try {  
                        X509TrustManager xtm = new X509TrustManager() {  
                            @Override  
                            public void checkClientTrusted(X509Certificate[] chain, String authType) {  
                            }  
  
                            @Override  
                            public void checkServerTrusted(X509Certificate[] chain, String authType) {  
                            }  
  
                            @Override  
                            public X509Certificate[] getAcceptedIssuers() {  
                                X509Certificate[] x509Certificates = new X509Certificate[0];  
                                return x509Certificates;  
                            }  
                        };  
  
                        SSLContext sslContext = null;  
                        try {  
                            sslContext = SSLContext.getInstance("SSL");  
  
                            sslContext.init(null, new TrustManager[]{xtm}, new SecureRandom());  
  
                        } catch (NoSuchAlgorithmException e) {  
                            e.printStackTrace();  
                        } catch (KeyManagementException e) {  
                            e.printStackTrace();  
                        }  
                        HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {  
                            @Override  
                            public boolean verify(String hostname, SSLSession session) {  
                                return true;  
                            }  
                        };  
  
                        // 指定缓存路径,缓存大小100Mb  
                        Cache cache = new Cache(new File(mContext.getCacheDir(), "HttpCache"), 1024 * 1024 * 100);  
                        mOkHttpClient = new OkHttpClient.Builder().  
                                addInterceptor(mRewriteCacheControlInterceptor).  
                                retryOnConnectionFailure(false).  
                                connectTimeout(30, TimeUnit.SECONDS).  
                                sslSocketFactory(sslContext.getSocketFactory()).  
                                hostnameVerifier(DO_NOT_VERIFY).  
                                cache(cache).  
                                build();  
                    } catch (Exception e) {  
                        e.printStackTrace();  
                    }  
                }  
            }  
        }  
    }  
  
  
    private static Response onSuccess(Response originalResponse, String content) {  
        return originalResponse.newBuilder().  
                body(ResponseBody.create(null, content)).  
                build();  
    }  
  
  
    /** 
     * errorCode 不为200 
     * 
     * @param msgBean 
     */  
    private static void onFailed(ResponseMessageBean msgBean) {  
        String alert = "";  
        if (msgBean == null) {  
            return;  
        }  
        if (msgBean.errorCode != 200) {  
            if (msgBean.errorCode == 401) {  
                Observable.create(new Observable.OnSubscribe() {  
                    @Override  
                    public void call(Subscriber subscriber) {  
                        DialogUtils.alertUserUnauthorized(mContext);  
                    }  
                }).subscribeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() {  
                    @Override  
                    public void onCompleted() {  
                    }  
  
                    @Override  
                    public void onError(Throwable e) {  
                    }  
  
                    @Override  
                    public void onNext(Object o) {  
                    }  
                });  
  
                return;  
            } else if (msgBean.errorCode == 301) {  
                alert = "服务器繁忙,请稍后再试";  
            } else if (msgBean.errorCode == 302) {  
                alert = "此次访问已失效哦";  
            } else if (msgBean.errorCode == 403) {  
                alert = "接口临时关闭,请稍后再试";  
            } else if (msgBean.errorCode == 500) {  
                alert = "服务器繁忙,请稍后再试";  
            } else if (msgBean.errorCode == -1) {  
                showError = true;  
                if (msgBean.moreInfo != null) {  
                    alert = msgBean.moreInfo.toString();  
                }  
            } else {  
                return;  
            }  
            final String alertStr = alert;  
  
            Observable.create(new Observable.OnSubscribe() {  
                @Override  
                public void call(Subscriber subscriber) {  
                    //这里有 window bad token 错误  
                    try {  
                        if (showError && !TextUtils.isEmpty(alertStr)) {  
                            ToastUtils.showToast(mContext, alertStr);  
                            showError = false;  
                        }  
                    } catch (Exception e) {  
                        e.printStackTrace();  
                    }  
                }  
            }).subscribeOn(AndroidSchedulers.mainThread()).subscribe();  
        }  
    }  
  
    /** 
     * 统一处理请求头部数据 
     * 
     * @return 
     */  
  
    private static Request.Builder createRequestHeader(Request.Builder builder) {  
        builder.header("Content-Type",  
                "application/x-www-form-urlencoded");  
        builder.header("User-Agent", getUserAgent());  
        return builder;  
    }  
  
  
    public static String getUserAgent() {  
        UserAgentBean userAgent = new UserAgentBean();  
        userAgent.setDeviceToken(AppUtils.getDeviceId(mContext));  
        userAgent.setClient("Android");  
        userAgent.setChannel("xunbao");  
        if (User.getCurrent() != null) {  
            userAgent.setUserId(User.getCurrent().getId());  
        }  
        PackageInfo info = AppUtils.getPackageInfo(mContext);  
        if (info != null) {  
            userAgent.setBuild(info.versionCode + "");  
            userAgent.setVersion(info.versionName);  
        }  
        userAgent.setScreenSize(  
                DisplayUtils.getScreenSize(mContext));  
        userAgent.setSafeToken(SharePerferenceUtils.getString(mContext,PreferenceConstant.SAFE_TOKEN));  
        return userAgent.toString();  
    }  
  
}  






你可能感兴趣的:(Retrofit+RxJava 完美封装)