retrofit+rxjava+okhttp网络框架之二次封装


retrofit+rxjava的是这几年很流行的一种网络框架,开发者也提供了丰富的方法。
之所以进行二次封装,就是因为retrofit+rxjava的链式调用太方便了,不符合单一性原则,
管理起来比较麻烦。主要目的是二次封装后,和项目有很高的契合度更高。

说一下封装思路,由于其本身调用方便,具体方法就不做封装了。

第一 retrofit对象封装。

第二 封装okhttp拦截器,用于添加头参数,拦截错误日志。

第三 响应处理分发封装,对链接失败,链接错误,请求错误,请求成功对应处理。

下面直接上代码:

先看一下封装后的使用,具体的封装步骤,后面会有。

RetrofitHelper.getRetrofitInstance(null)
                .create(Api.class)
                .login()
                .compose(RxJavaUtils.setThread())
                .subscribe(new BaseObserver(context) {
                    @Override
                    public void onSuccess(BaseBean response) {
                        Log.d("nade", "onSuccess: 成功处理");
                    }
                });
二次封装后,使用非常简单。

下面是具体步骤:
一 retrofit封装

1 retrofit对象封装

public class RetrofitHelper {

扫描二维码关注公众号,回复: 9767171 查看本文章

    /**
     * retrofit 请求助手
     *
     * @param
     * @return retrofit 对象
     *
     */
   public static Retrofit getRetrofitInstance(@Nullable Request.Builder request){
       Retrofit.Builder builder = new Retrofit.Builder();
       Retrofit retrofit = builder.baseUrl(URL.host)
               .client(OkClient.getOkClientInstance(new BaseInterceptor(request)).getHttpClient())
               .addConverterFactory(GsonConverterFactory.create())
               .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
               .build();
       return retrofit;
   }
}

2 我们还需要一个OkClient

public class OkClient {
    private OkHttpClient httpClient;
    private static OkClient okClient;
    private OkClient(Interceptor interceptor){
        OkHttpClient.Builder okBuilder = new OkHttpClient.Builder()
                .addInterceptor(interceptor)   // 头参数
                .addInterceptor(new RetryInterceptor(RetryInterceptor.COUNT))  // 重连机制
                .writeTimeout(NetConstant.NET_TIME_OUT, TimeUnit.SECONDS)
                .readTimeout(NetConstant.NET_TIME_OUT, TimeUnit.SECONDS)
                .connectTimeout(NetConstant.NET_TIME_OUT, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .addInterceptor(new PrintLogInterceptor())   // 日志打印 用于请求失败分析
                .addInterceptor(new ErrorStatuInterceptor());  // 错误状态拦截,用于错误状态app内部转换并处理后续动作
        httpClient = okBuilder.build();
    }
    public static OkClient getOkClientInstance(Interceptor interceptor){
        if (null == okClient) {
            synchronized (OkClient.class){
                if (null == okClient){
                    okClient = new OkClient(interceptor);
                }
            }
        }
        return okClient;
    }
        // 返回client 对象
    public OkHttpClient getHttpClient() {
        return httpClient;
    }


第二 封装okhttp拦截器,用于添加头参数,拦截错误日志。

头参数拦截器

public class HeadsInterceptor implements Interceptor {
    // 用于添加头参数 开放请求体,可设置请求头参数
    private Request.Builder request;

    /**
     * 请求头参数 可以为空 request.addHeader("key","value");
     * @param request
     */
    public HeadsInterceptor(@Nullable Request.Builder request) {
        this.request = request;
        
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        if (null != request) {
            return chain.proceed(request.build());
        }
        return null;
    }
}


重试拦截器

public class RetryInterceptor implements Interceptor {
    public static final int COUNT = 2; // 默认为2(请求总量3)
    private static final String TAG = "RetryInterceptor";

    private int maxRetry = 3;//最大重试次数

    //    延迟
    private long delay = 500;
    //    叠加延迟
    private long increaseDelay = 3*1000;


    public RetryInterceptor() {

    }

    public RetryInterceptor(int maxRetry) {
        this.maxRetry = maxRetry;
    }

    public RetryInterceptor(int maxRetry, long delay) {
        this.maxRetry = maxRetry;
        this.delay = delay;
    }

    public RetryInterceptor(int maxRetry, long delay, long increaseDelay) {
        this.maxRetry = maxRetry;
        this.delay = delay;
        this.increaseDelay = increaseDelay;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {

        RetryWrapper retryWrapper = proceed(chain);

        while (retryWrapper.isNeedReTry()) {
            retryWrapper.retryNum++;
            try {
                Thread.sleep(delay + (retryWrapper.retryNum - 1) * increaseDelay);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            proceed(chain, retryWrapper.request, retryWrapper);
        }
        return retryWrapper.response == null ? chain.proceed(chain.request()) : retryWrapper.response;
    }

    private RetryWrapper proceed(Chain chain) throws IOException {
        Request request = chain.request();
        RetryWrapper retryWrapper = new RetryWrapper(request, maxRetry);

        proceed(chain, request, retryWrapper);

        return retryWrapper;
    }

    private void proceed(Chain chain, Request request, RetryWrapper retryWrapper) throws IOException {
        try {
            Response response = chain.proceed(request);
            retryWrapper.setResponse(response);
        } catch (SocketException | SocketTimeoutException e) {
            //e.printStackTrace();
        }
    }

    static class RetryWrapper {
        volatile int retryNum = 0;//假如设置为3次重试的话,则最大可能请求5次(默认1次+3次重试 + 最后一次默认)
        Request request;
        Response response;
        private int maxRetry;

        public RetryWrapper(Request request, int maxRetry) {
            this.request = request;
            this.maxRetry = maxRetry;
        }

        public void setResponse(Response response) {
            this.response = response;
        }

        Response response() {
            return this.response;
        }

        Request request() {
            return this.request;
        }

        public boolean isSuccessful() {
            return response != null && response.isSuccessful();
        }

        public boolean isNeedReTry() {
            return !isSuccessful() && retryNum < maxRetry;
        }

        public void setRetryNum(int retryNum) {
            this.retryNum = retryNum;
        }

        public void setMaxRetry(int maxRetry) {
            this.maxRetry = maxRetry;
        }
    }
}

日志打印拦截器

public class PrintLogInterceptor implements Interceptor {

    /**
     * 打印日志 各种日志 请求参数 等
     */

    String TAG = "nade";
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        Log.d(TAG, "url     =  : " + request.url());
        Log.d(TAG, "method  =  : " + request.method());
        Log.d(TAG, "headers =  : " + request.headers());
        Log.d(TAG, "body    =  : " + request.body());
        Log.d(TAG, "code     =  : " + response.code());
        Log.d(TAG, "message  =  : " + response.message());
        Log.d(TAG, "protocol =  : " + response.protocol());
        if (response.body() != null && response.body().contentType() != null) {
            MediaType mediaType = response.body().contentType();
            String string = response.body().string();
            Log.d(TAG, "mediaType =  :  " + mediaType.toString());
            Log.d(TAG, "string    =  : " + decode(string));
            ResponseBody responseBody = ResponseBody.create(mediaType, string);
            return response.newBuilder().body(responseBody).build();
        } else {
            return response;
        }
    }

    private String decode(String unicodeStr) {
        if (unicodeStr == null) {
            return null;
        }
        StringBuffer retBuf = new StringBuffer();
        int maxLoop = unicodeStr.length();
        for (int i = 0; i < maxLoop; i++) {
            if (unicodeStr.charAt(i) == '\\') {
                if ((i < maxLoop - 5) && ((unicodeStr.charAt(i + 1) == 'u') || (unicodeStr.charAt(i + 1) == 'U')))
                    try {
                        retBuf.append((char) Integer.parseInt(unicodeStr.substring(i + 2, i + 6), 16));
                        i += 5;
                    } catch (NumberFormatException localNumberFormatException) {
                        retBuf.append(unicodeStr.charAt(i));
                    }
                else
                    retBuf.append(unicodeStr.charAt(i));
            } else {
                retBuf.append(unicodeStr.charAt(i));
            }
        }
        return retBuf.toString();
    }

}


错误状态拦截器


public class ErrorStatuInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        if (response.body() != null && response.body().contentType() != null) {
            return response.newBuilder().body(errorResponse(response,request)).build();
        } else {
            return response;
        }

    }
    public ResponseBody errorResponse(Response response, Request request){
        MediaType mediaType = response.body().contentType();
        String s = null;
        try {
            s = response.body().string();
        } catch (IOException e) {
            e.printStackTrace();
        }
        BaseBean bean = GsonInstance.getInstance().fromJson(s, BaseBean.class);
        if (bean != null && bean.getHead() != null && TextUtils.equals(bean.getCode(),"200")){// 成功
            return ResponseBody.create(mediaType,s);
        }else {// 成功
            return ResponseBody.create(mediaType,s);
        }

    }
}

第三 响应处理分发封装,对链接失败,链接错误,请求错误,请求成功对应处理。


public abstract class BaseObserver<T extends BaseBean> implements Observer<T> {
    private static final String CONNECT_ERROR = "网络连接失败,请检查网络";
    private static final String CONNECT_TIMEOUT = "连接超时,请稍后再试";
    private static final String BAD_NETWORK = "服务器异常";
    private static final String PARSE_ERROR = "解析服务器响应数据失败";
    private static final String UNKNOWN_ERROR = "未知错误";
    private static final String RESPONSE_RETURN_ERROR = "服务器返回数据失败";

    private Disposable dis;
    private boolean isShowProgress = true;
    private ProDialog load;

    @Override
    public void onSubscribe(Disposable d) {
        this.dis = d;
        if (isShowProgress){
            showProgress();
        }
    }

    @Override
    public void onNext(T o) {
        hideProgress();
        onDestory();
        if (TextUtils.equals(o.getCode(),"200")) {
            onSuccess(o);
        }else {
            onFailed(o);
        }
    }

    @Override
    public void onComplete() {
        hideProgress();
    }

    @Override
    public void onError(Throwable e) {

        hideProgress();
        if (e instanceof retrofit2.HttpException) {
            //HTTP错误
            onException(ExceptionReason.BAD_NETWORK);
        } else if (e instanceof ConnectException || e instanceof UnknownHostException) {
            //连接错误
            onException(ExceptionReason.CONNECT_ERROR);
        } else if (e instanceof InterruptedIOException) {
            //连接超时
            onException(ExceptionReason.CONNECT_TIMEOUT);
        } else if (e instanceof JsonParseException || e instanceof JSONException || e instanceof ParseException) {
            //解析错误
            onException(ExceptionReason.PARSE_ERROR);
        } else {
            //其他错误
            onException(ExceptionReason.UNKNOWN_ERROR);
        }

    }

    private Context context;

    public BaseObserver(Context context) {
        this.context = context;
    }

    public BaseObserver(Context context, boolean isShowProgress) {
        this.context = context;
        this.isShowProgress = isShowProgress;
    }

    public Context getContext(){
        return context;
    }

    // 请求成功
    public abstract void onSuccess(T response);


    // 请求失败
    public void onFailed(BaseBean bean){

    };

    // 展示进度
    protected void showProgress(){
        load = new ProDialog.Builder(context).createLoad();
        load.showLoading();


    }
    // 关闭进度
    protected void hideProgress(){
        if (load != null) {
            load.closeLoading();
        }
    }
    /**
     * 网络请求失败原因
     */
    public enum ExceptionReason {
        /**
         * 解析数据失败
         */
        PARSE_ERROR,
        /**
         * 网络问题
         */
        BAD_NETWORK,
        /**
         * 连接错误
         */
        CONNECT_ERROR,
        /**
         * 连接超时
         */
        CONNECT_TIMEOUT,
        /**
         * 未知错误
         */
        UNKNOWN_ERROR
    }
    private void onException(ExceptionReason reason) {
        switch (reason) {
            case CONNECT_ERROR:
                Toast.makeText(context, CONNECT_ERROR, Toast.LENGTH_SHORT).show();
                break;

            case CONNECT_TIMEOUT:
                Toast.makeText(context, CONNECT_TIMEOUT, Toast.LENGTH_SHORT).show();
                break;

            case BAD_NETWORK:
                Toast.makeText(context, BAD_NETWORK, Toast.LENGTH_SHORT).show();
                break;

            case PARSE_ERROR:
                Toast.makeText(context, PARSE_ERROR, Toast.LENGTH_SHORT).show();
                break;

            case UNKNOWN_ERROR:
            default:
                Toast.makeText(context, UNKNOWN_ERROR, Toast.LENGTH_SHORT).show();
                break;
        }
    }


    // 取消请求
    public void cancelRequest(){
        if (dis != null && !dis.isDisposed()) {
            dis.dispose();
        }
    }

    // 请求成功后,资源释放。
    public void onDestory(){
        cancelRequest();
    }
}


RxJavaUtils

public class RxJavaUtils {
    public static <T> ObservableTransformer<T, T> setThread() {
        return upstream -> upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers
                .mainThread());
    }
}


到此处就完结了。剩余一些零星点点的参数和敞亮,自己设置就好了。
需要源码可以私信我或者qq加我。

发布了76 篇原创文章 · 获赞 82 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/Naide_S/article/details/104804220