Retrofit2和Rxjava2封裝思路
阿新 • • 發佈:2019-02-13
//ApiService.java
public interface ApiService {
@POST("app/api")
Observable<Response2> request2(@Body Request2 request);
/**
* Create a new ApiService
*/
class Factory {
private Factory() { }
public static ApiService createService( ) {
OkHttpClient .Builder builder = new OkHttpClient().newBuilder();
builder.readTimeout(10, TimeUnit.SECONDS);
builder.connectTimeout(9, TimeUnit.SECONDS);
if (BuildConfig.DEBUG) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor .Level.BODY);
builder.addInterceptor(interceptor);
}
builder.addInterceptor(new HeaderInterceptor());
OkHttpClient client = builder.build();
Retrofit retrofit =
new Retrofit.Builder().baseUrl(ApiService.ENDPOINT)
.client(client )
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
return retrofit.create(ApiService.class);
}
}
}
使用起來如下
ApiService mApiService = ApiService.Factory.createService();
mApiService.request1(request)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Response1>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Response1 response) {
int code = response.getCode();
switch (code) {
case 1: //do something
break;
case -101://do something
break;
case -102: //do something
break;
default:
break;
}
}
});
最終目標封裝成如下
@POST("order/getAllOrders")
Observable<HttpResult<List<Order>>> postOrderList(@Body OrderRequest request);
ServiceFactory.orderApi()
.postOrderListState(mRequest)
.compose(new DefaultTransformer<List<Order>>())
.subscribe(new CommonSubscriber<List<Order>>(mContext) {
@Override
public void onNext(List<Order> data) {
}
@Override
protected void onError(ApiException ex) {
super.onError(ex);
ToastUtil.showShort(mContext, ex.message);
}
});
提取ApiService的Api類的建立
上面的Factory一起建立一個ServiceFactory
//https 支援
HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory(null, null, null);
sClient = new OkHttpClient().newBuilder()
.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
//設定連結時間
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
//設定攔截器
.addInterceptor(new HeaderInterceptor())
.addInterceptor(new TokenInterceptor())
.addNetworkInterceptor(new HttpLoggingInterceptor().setLevel(BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.NONE))
.retryOnConnectionFailure(true)
//斷網重連
.build();
OkHttpUtils.initClient(sClient);
sRetrefit = new Retrofit.Builder()
.client(sClient)
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(MyApplication.getmGson()))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
DefaultTransformer封裝
首先得了解操作符compose()和flatMap()有啥區別呢。他們都是發射出Observable,是不是就是說他們都可以複用一系列操作符呢?
compose() 是針對 Observable 自身進行變換。
compose()是唯一一個能從流中獲取原生Observable
的方法,因此,影響整個流的操作符(像subscribeOn()和observeOn())需要使用compose(),相對的,如果你在flatMap()中使用subscribeOn()/observeOn(),它隻影響你建立的flatMap()中的Observable,而不是整個流。當你建立一個Observable流並且內聯了一堆操作符以後,compose()會立即執行,flatMap()則是在onNext()被呼叫以後才會執行,換句話說,flatMap()轉換的是每個專案,而compose()轉換的是整個流。
flatMap()一定是低效率的,因為他每次呼叫onNext()之後都需要建立一個新的Observable,compose()是操作在整個流上的。
這裡沒有出錯就轉成HttpResult出錯了就丟擲異常
// 通過對返回碼進行業務判斷決定是返回錯誤還是正常取資料
if (httpResult.getCode() != ErrorType.SUCCESS) {
throw new ServerException(httpResult.getMessage(), httpResult.getCode());
}
return httpResult.getData();
.onErrorResumeNext(new Func1<Throwable, Observable<? extends T>>() {
@Override
public Observable<? extends T> call(Throwable throwable) {
//ExceptionEngine為處理異常的驅動器
return Observable.error(ExceptionEngine.handleException(throwable));
}
});
丟擲異常以後再走.onErrorResumeNext 方法
public class ServerException extends RuntimeException {
// 異常處理,為速度,不必要設定getter和setter
public int code;
public String message;
public ServerException(String message, int code) {
super(message);
this.code = code;
this.message = message;
}
}
public class ExceptionEngine {
//對應HTTP的狀態碼
private static final int UNAUTHORIZED = 401;
private static final int FORBIDDEN = 403;
private static final int NOT_FOUND = 404;
private static final int REQUEST_TIMEOUT = 408;
private static final int INTERNAL_SERVER_ERROR = 500;
private static final int BAD_GATEWAY = 502;
private static final int SERVICE_UNAVAILABLE = 503;
private static final int GATEWAY_TIMEOUT = 504;
public static ApiException handleException(Throwable e) {
ApiException ex;
if (e instanceof HttpException) { //HTTP錯誤
HttpException httpException = (HttpException) e;
ex = new ApiException(e, ErrorType.HTTP_ERROR);
switch (httpException.code()) {
case UNAUTHORIZED:
ex.message = "當前請求需要使用者驗證";
break;
case FORBIDDEN:
ex.message = "伺服器已經理解請求,但是拒絕執行它";
break;
case NOT_FOUND:
ex.message = "伺服器異常,請稍後再試";
break;
case REQUEST_TIMEOUT:
ex.message = "請求超時";
break;
case GATEWAY_TIMEOUT:
ex.message = "作為閘道器或者代理工作的伺服器嘗試執行請求時,未能及時從上游伺服器(URI標識出的伺服器,例如HTTP、FTP、LDAP)或者輔助伺服器(例如DNS)收到響應";
break;
case INTERNAL_SERVER_ERROR:
ex.message = "伺服器遇到了一個未曾預料的狀況,導致了它無法完成對請求的處理";
break;
case BAD_GATEWAY:
ex.message = "作為閘道器或者代理工作的伺服器嘗試執行請求時,從上游伺服器接收到無效的響應";
break;
case SERVICE_UNAVAILABLE:
ex.message = "由於臨時的伺服器維護或者過載,伺服器當前無法處理請求";
break;
default:
ex.message = "網路錯誤"; //其它均視為網路錯誤
break;
}
return ex;
} else if (e instanceof ServerException) { //伺服器返回的錯誤
ServerException resultException = (ServerException) e;
ex = new ApiException(resultException, resultException.code);
ex.message = resultException.message;
return ex;
} else if (e instanceof JsonSyntaxException) {
// ex = new ApiException(e, ErrorType.TOKEN_INVALID);
// ex.message = "Token失效"; //均視為解析錯誤
ex = new ApiException(e, ErrorType.PARSE_ERROR);
ex.message = "返回資料錯誤"; //均視為解析錯誤
return ex;
} else if (e instanceof JsonParseException
|| e instanceof JSONException
|| e instanceof ParseException) {
ex = new ApiException(e, ErrorType.PARSE_ERROR);
ex.message = "解析錯誤"; //均視為解析錯誤
return ex;
} else if (e instanceof ConnectException || e instanceof SocketTimeoutException || e instanceof ConnectTimeoutException) {
ex = new ApiException(e, ErrorType.NETWORD_ERROR);
ex.message = "連線失敗"; //均視為網路錯誤
return ex;
} else {
ex = new ApiException(e, ErrorType.UNKNOWN);
ex.message = "未知錯誤"; //未知錯誤
return ex;
}
}
最後再走CommonSubscriber.error