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 {

/**
 * 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 implements Observer {
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 ObservableTransformer setThread() {
return upstream -> upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers
.mainThread());
}
}

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

你可能感兴趣的:(retrofit+rxjava+okhttp网络框架之二次封装)