前言
Retrofit
和RxJava
已經(jīng)出來很久了油讯,很多前輩寫了很多不錯的文章,在此不得不感謝這些前輩無私奉獻的開源精神延欠,能讓我們站在巨人的肩膀上望得更遠陌兑。
Retrofit:Retrofit是Square 公司開發(fā)的一款針對Android 網(wǎng)絡(luò)請求的框架。
RxJava:RxJava 是一個鏈式調(diào)用的異步框架由捎。
RxJava在 GitHub 主頁上的自我介紹是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一個在 Java VM 上使用可觀測的序列來組成異步的兔综、基于事件的程序的庫)。這就是 RxJava 狞玛,概括得非常精準软驰。
一言以辟之,就是讓異步操作變得非常簡單心肪。
各自職責:Retrofit 負責請求的數(shù)據(jù)和請求的結(jié)果锭亏,使用接口的方式呈現(xiàn),OkHttp 負責請求的過程硬鞍,RxJava 負責異步慧瘤,各種線程之間的切換。
RxJava
的使用參考-->給 Android 開發(fā)者的 RxJava 詳解
Retrofit
的使用參考-->Android Retrofit 2.0使用
本文內(nèi)容是基于Retrofit + RxJava
做的一些優(yōu)雅的封裝固该。參考了很多文章加入了一些自己的理解锅减,請多指教。
先引入依賴
build.gradle
// Okhttp庫
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.1'
// Retrofit庫
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
//RxJava
implementation 'io.reactivex.rxjava2:rxjava:2.0.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
在此之前伐坏,
先來聊聊簡單使用怔匣,(優(yōu)雅封裝見下文)
1、先寫一個接口Service
interface APIService {
@GET("user/login" )
Call<UserInfo> login(@Query("username") String username,@Query("password")String password);
}
2桦沉、獲取Call執(zhí)行網(wǎng)絡(luò)請求
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build();
APIService service = retrofit.create(APIService.class);
Call<UserInfo> call = service.login("張曉宇", "is sb");
call.enqueue(new Callback<UserInfo>() {
@Override
public void onResponse(Call<UserInfo> call, Response<UserInfo> response) {
//請求成功
}
@Override
public void onFailure(Call<UserInfo> call, Throwable t) {
//請求失敗
}
});
以上就是Retrofit的簡單使用每瞒。但是實際項目中,我們肯定不會這么寫纯露,這樣寫完全不符合我們寫代碼的優(yōu)雅性和簡潔性独泞。所以,我們要對它進行優(yōu)雅的封裝苔埋。
Retrofit+RxJava優(yōu)雅的封裝
1懦砂、請求實體類與返回實體類的封裝
BaseRequestEntity.java
public class BaseRequestEntity <T>{
private HeaderEntity header;
private T data;
public HeaderEntity getHeader() {
return header;
}
public void setHeader(HeaderEntity header) {
this.header = header;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
BaseResponseEntity.java
public class BaseResponseEntity<T> {
private int errorCode;
private String errorMsg;
private T data;
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
2、請求接口服務(wù)類封裝
ObservableAPI.java
/**
* 接口服務(wù)
**/
public interface ObservableAPI {
/**
* 登錄
*/
@POST(URL.URL_LOGIN)
Observable<BaseResponseEntity<LoginResponseEntity>> login(@Body BaseRequestEntity<LoginRequestEntity> requestEntity);
}
3、ObservableManager封裝(請求接口傳參封裝)
ObservableManager.java
public class ObservableManager {
private static class SingletonHolder {
static final ObservableManager INSTANCE = new ObservableManager();
}
public static ObservableManager getInstance() {
return ObservableManager.SingletonHolder.INSTANCE;
}
/**
* login
*/
public BaseRequestEntity<LoginRequestEntityl> getLoginRequestEntity() {
BaseRequestEntity<LoginRequestEntity> requestModel = new BaseRequestEntity<>();
requestModel.setHeader(HeaderUtils.setHeaderModel());
LoginRequestEntity loginRequestModel = new LoginRequestEntity();
requestModel.setData(loginRequestModel);
return requestModel;
}
}
4荞膘、Retrofit封裝
RetrofitHandler.java
public class RetrofitHandler {
private static Retrofit mRetrofit;
private static OkHttpClient mOkHttpClient;
private static RetrofitHandler mRetrofitHandler;
private static ObservableAPI mObservableAPI;
private RetrofitHandler() {
initRetrofit();
}
public static synchronized RetrofitHandler getInstance() {
if (mRetrofitHandler == null) {
synchronized (RetrofitHandler.class) {
if (mRetrofitHandler == null) {
mRetrofitHandler = new RetrofitHandler();
}
}
}
return mRetrofitHandler;
}
/**
* 獲取 Retrofit
*/
private void initRetrofit() {
initOkHttpClient();
mRetrofit = new Retrofit.Builder()
.baseUrl(URL.BASE_URL)
//JSON轉(zhuǎn)換器,使用Gson來轉(zhuǎn)換
.addConverterFactory(GsonConverterFactory.create())
//RxJava適配器
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(mOkHttpClient)
.build();
mObservableAPI = mRetrofit.create(ObservableAPI.class);
}
/**
* 單例模式獲取 OkHttpClient
*/
private static void initOkHttpClient() {
if (mOkHttpClient == null) {
synchronized (RetrofitHandler.class) {
if (mOkHttpClient == null) {
// 指定緩存路徑,緩存大小100Mb
Cache cache = new Cache(new File(HttpConfig.DIR_CACHE_FILE, "HttpCache"),
1024 * 1024 * 100);
mOkHttpClient = new OkHttpClient.Builder()
//設(shè)置連接超時時間
.connectTimeout(HttpConfig.HTTP_TIME_OUT_TIME, TimeUnit.SECONDS)
//設(shè)置讀取超時時間
.readTimeout(HttpConfig.HTTP_TIME_OUT_TIME, TimeUnit.SECONDS)
//設(shè)置寫入超時時間
.writeTimeout(HttpConfig.HTTP_TIME_OUT_TIME, TimeUnit.SECONDS)
//默認重試一次
.retryOnConnectionFailure(true)
//添加請求頭攔截器
.addInterceptor(InterceptorHelper.getHeaderInterceptor())
//添加日志攔截器
.addInterceptor(InterceptorHelper.getLogInterceptor())
//添加緩存攔截器
.addInterceptor(InterceptorHelper.getCacheInterceptor())
//添加重試攔截器
.addInterceptor(InterceptorHelper.getRetryInterceptor())
// 信任Https,忽略Https證書驗證
// https認證,如果要使用https且為自定義證書 可以去掉這兩行注釋罚随,并自行配制證書。
.sslSocketFactory(SSLSocketTrust.getSSLSocketFactory())
.hostnameVerifier(SSLSocketTrust.getHostnameVerifier())
//緩存
.cache(cache)
.build();
}
}
}
}
/**
* 對外提供調(diào)用 API的接口
*
* @return
*/
public ObservableAPI getAPIService() {
return mObservableAPI;
}
}
5羽资、攔截器封裝(請求頭攔截器淘菩、日志攔截器、緩存攔截器屠升、重試攔截器等)
InterceptorHelper.java
/**
* @author wy
* @description 攔截器工具類
*/
public class InterceptorHelper {
public static String TAG = "Interceptor";
/**
* 日志攔截器
*/
public static HttpLoggingInterceptor getLogInterceptor() {
return new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Log.w(TAG, "LogInterceptor---------: " + message);
}
}).setLevel(HttpLoggingInterceptor.Level.BODY);//設(shè)置打印數(shù)據(jù)的級別
}
/**
* 緩存攔截器
*
* @return
*/
public static Interceptor getCacheInterceptor() {
return new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//CONTEXT不能為空
if (!NetworkUtils.isConnected(PalApplication.getInstance().getApplicationContext())) {
int maxStale = 4 * 7 * 24 * 60; // 離線時緩存保存4周,單位:秒
CacheControl tempCacheControl = new CacheControl.Builder()
.onlyIfCached()
.maxStale(maxStale, TimeUnit.SECONDS)
.build();
request = request.newBuilder()
.cacheControl(tempCacheControl)
.build();
}
return chain.proceed(request);
}
};
}
/**
* 重試攔截器
*
* @return
*/
public static Interceptor getRetryInterceptor() {
return new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
int maxRetry = 10;//最大重試次數(shù)
int retryNum = 5;//假如設(shè)置為3次重試的話潮改,則最大可能請求4次(默認1次+3次重試)
Request request = chain.request();
Response response = chain.proceed(request);
while (!response.isSuccessful() && retryNum < maxRetry) {
retryNum++;
response = chain.proceed(request);
}
return response;
}
};
}
/**
* 請求頭攔截器
*
* @return
*/
public static Interceptor getHeaderInterceptor() {
return new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
//在這里你可以做一些想做的事,比如token失效時,重新獲取token
//或者添加header等等
Request originalRequest = chain.request();
if (null == originalRequest.body()) {
return chain.proceed(originalRequest);
}
Request compressedRequest = originalRequest.newBuilder()
.header("Content-Encoding", "gzip")
.header("User-Agent", "OkHttp Headers.java")
.addHeader("Accept", "application/json; q=0.5")
.addHeader("Accept", "application/vnd.github.v3+json")
.addHeader("Accept-Encoding", "identity")
// .addHeader(Constants.WEB_TOKEN, webi_token)
.build();
Response proceed = chain.proceed(compressedRequest);
return proceed;
}
};
}
}
6、BaseObserver封裝(請求失敗腹暖、網(wǎng)絡(luò)異常汇在、接口錯誤、加載窗口等處理)
BaseObserver.java
public abstract class BaseObserver<T> implements Observer<BaseResponseEntity<T>> {
protected Context mContext;
public BaseObserver() {
}
public BaseObserver(Context cxt) {
this.mContext = cxt;
}
@Override
public void onSubscribe(Disposable d) {
onRequestStart();
}
@Override
public void onNext(BaseResponseEntity<T> tBaseEntity) {
onRequestEnd();
String message_common = "Oops, something went wrong. Please try again.";
if (tBaseEntity.getErrorCode()==0) {//成功
try {
onSuccess(tBaseEntity);
} catch (Exception e) {
e.printStackTrace();
}
} else {
try {
if (!CommonUtils.isEmptyOrNull(tBaseEntity.getErrorMsg())) {
onFailure(tBaseEntity.getErrorMsg());
} else {
onFailure(message_common);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onError(Throwable e) {
onRequestEnd();
String message_common = "Oops, something went wrong. Please try again.";
String msg_timeout = "Oops, connection timeout, please try again later";
try {
if (e instanceof ConnectException
|| e instanceof TimeoutException
|| e instanceof NetworkErrorException
|| e instanceof UnknownHostException) {
onFailure(msg_timeout);
} else {
onFailure(message_common);
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
@Override
public void onComplete() {
}
/**
* 返回成功
*
* @param tBaseEntity
*/
protected abstract void onSuccess(BaseResponseEntity<T> tBaseEntity);
/**
* 返回失敗
*
* @param errorMessage
*/
protected abstract void onFailure(String errorMessage);
/**
* 請求開始
*/
protected void onRequestStart() {
showProgressDialog();
}
/**
* 請求結(jié)束
*/
protected void onRequestEnd() {
closeProgressDialog();
}
/**
* 加載彈窗
*/
public void showProgressDialog() {
}
/**
* 關(guān)閉加載彈窗
*/
public void closeProgressDialog() {
}
}
7脏答、調(diào)度類封裝
RxTransformerHelper.java
/**
* 調(diào)度類
*/
public class RxTransformerHelper {
public static <T> ObservableTransformer<T, T> observableIO2Main(final Context context) {
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource<T> apply(Observable<T> upstream) {
return upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
};
}
}
8糕殉、使用方式
private void login() {
RetrofitHandler.getInstance().getAPIService()
.login(ObservableManager.getInstance().getLoginRequestEntity())
.compose(RxTransformerHelper.<BaseResponseEntity<LoginResponseEntity>>observableIO2Main(this))
.subscribe(new BaseObserver<LoginResponseEntity>() {
@Override
protected void onSuccess(BaseResponseEntity<LoginResponseEntity> responseEntity) {
showSuccessDialog("Success");
}
@Override
protected void onFailure(String errorMessage) {
showErrorDialog(errorMessage);
}
});
}