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
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
return upstream -> upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers
.mainThread());
}
}
到此处就完结了。剩余一些零星点点的参数和敞亮,自己设置就好了。
需要源码可以私信我或者qq加我。