深入淺出RxJava+Retrofit+OkHttp網(wǎng)絡請求
淺談RxJava+Retrofit+OkHttp 封裝使用 之前發(fā)出后收到很多朋友的關注,原本只是自己學習后的一些經(jīng)驗總結,但是有同學運用到實戰(zhàn)當中,這讓我很惶恐,所有后續(xù)一直更新了很多次版本,有些地方難免有所變動導致之前的博客有所出入,正好最近受到掘金邀請內測博客,所以決定重新寫一版,按照最后迭代完成的封裝詳細的講述一遍,歡迎大家關注!
注意:由于本章的特殊性,后續(xù)文章比較長而且復雜,涉及內容也很多,所以大家準備好茶水,前方高能預警。
簡介:
Retrofit: Retrofit是Square 公司開發(fā)的一款正對Android 網(wǎng)絡請求的框架。底層基于OkHttp 實現(xiàn),OkHttp 已經(jīng)得到了google 官方的認可。
OkHttp: 也是Square 開源的網(wǎng)絡請求庫
RxJava:RxJava 在 GitHub 主頁上的自我介紹是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一個在 Java VM 上使用可觀測的序列來組成異步的、基于事件的程序的庫)。這就是 RxJava ,概括得非常精準。總之就是讓異步操作變得非常簡單。
各自的職責:Retrofit 負責請求的數(shù)據(jù)和請求的結果,使用接口的方式呈現(xiàn),OkHttp 負責請求的過程,RxJava 負責異步,各種線程之間的切換。
RxJava + Retrofit + okHttp 已成為當前Android 網(wǎng)絡請求最流行的方式。
封裝成果
封裝完以后,具有如下功能:
1.Retrofit+Rxjava+okhttp基本使用方法
2.統(tǒng)一處理請求數(shù)據(jù)格式
3.統(tǒng)一的ProgressDialog和回調Subscriber處理
4.取消http請求
5.預處理http請求
6.返回數(shù)據(jù)的統(tǒng)一判斷
7.失敗后的retry封裝處理
8.RxLifecycle管理生命周期,防止泄露
實現(xiàn)效果:

具體使用
封裝后http請求代碼如下
// 完美封裝簡化版
private void simpleDo() {
SubjectPost postEntity = new SubjectPost(simpleOnNextListener,this);
postEntity.setAll(true);
HttpManager manager = HttpManager.getInstance();
manager.doHttpDeal(postEntity);
}
// 回調一一對應
HttpOnNextListener simpleOnNextListener = new HttpOnNextListener<List<Subject>>() {
@Override
public void onNext(List<Subject> subjects) {
tvMsg.setText("已封裝:\n" + subjects.toString());
}
/*用戶主動調用,默認是不需要覆寫該方法*/
@Override
public void onError(Throwable e) {
super.onError(e);
tvMsg.setText("失?。篭n" + e.toString());
}
};
是不是很簡單?你可能說這還簡單,好咱們對比一下正常使用Retrofit的方法
/**
* Retrofit加入rxjava實現(xiàn)http請求
*/
private void onButton9Click() {
//手動創(chuàng)建一個OkHttpClient并設置超時時間
okhttp3.OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(5, TimeUnit.SECONDS);
Retrofit retrofit = new Retrofit.Builder()
.client(builder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(HttpManager.BASE_URL)
.build();
/ 加載框
final ProgressDialog pd = new ProgressDialog(this);
HttpService apiService = retrofit.create(HttpService.class);
Observable<RetrofitEntity> observable = apiService.getAllVedioBy(true);
observable.subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Subscriber<RetrofitEntity>() {
@Override
public void onCompleted() {
if (pd != null && pd.isShowing()) {
pd.dismiss();
}
}
@Override
public void onError(Throwable e) {
if (pd != null && pd.isShowing()) {
pd.dismiss();
}
}
@Override
public void onNext(RetrofitEntity retrofitEntity) {
tvMsg.setText("無封裝:\n" + retrofitEntity.getData().toString());
}
@Override
public void onStart() {
super.onStart();
pd.show();
}
}
);
}
可能你發(fā)現(xiàn)確是代碼有點多,但是更加可怕的是,如果你一個activity或者fragment中多次需要http請求,你需要多次重復的寫回調處理(一個回到就有4個方法呀?。。。》凑沂侨淌懿涣耍?,而且以上處理還沒有做過多的判斷和錯誤校驗就如此復雜!~好了介紹完了,開始咱們的優(yōu)化之路吧!
項目結構:

Retrofit
咱家今天的主角來了,咱們也深入淺出一下了解下Retrofit使用,前方高能,如果你是深度Retrofit選手請直接跳過本節(jié)?。?!
1.首先確保在AndroidManifest.xml中請求了網(wǎng)絡權限
<uses-permission android:name="android.permission.INTERNET"/>
2.在app/build.gradle添加引用
/*rx-android-java*/ compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' compile 'com.trello:rxlifecycle:1.0' compile 'com.trello:rxlifecycle-components:1.0' /*rotrofit*/ compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.0.0' compile 'com.google.code.gson:gson:2.8.0'
3.常用注解
這里介紹一些常用的注解的使用
- @Query、@QueryMap:用于Http Get請求傳遞參數(shù)
- @Field:用于Post方式傳遞參數(shù),需要在請求接口方法上添加@FormUrlEncoded,即以表單的方式傳遞參數(shù)
- @Body:用于Post,根據(jù)轉換方式將實例對象轉化為對應字符串傳遞參數(shù).比如Retrofit添加GsonConverterFactory則是將body轉化為gson字符串進行傳遞
- @Path:用于URL上占位符
- @Part:配合@Multipart使用,一般用于文件上傳
- @Header:添加http header
- @Headers:跟@Header作用一樣,只是使用方式不一樣,@Header是作為請求方法的參數(shù)傳入,@Headers是以固定方式直接添加到請求方法上
ReTrofit基本使用:
首先給定一個測試接口文檔,后面的博客中我們都是用這個接口調試
/**
* @api videoLink 50音圖視頻鏈接
* @url http://www.izaodao.com/Api/AppFiftyToneGraph/videoLink
* @method post
* @param once_no bool(選填,ture無鏈接) 一次性獲取下載地址
* @return json array(
* ret:1成功,2失敗
* msg:信息
* data:{
* name:視頻名稱
* title:標題
* }
)
1.初始化retrofit
要向一個api發(fā)送我們的網(wǎng)絡請求 ,我們需要使用Retrofit builder類并指定service的base URL(通常情況下就是域名)。
String BASE_URL = " http://www.izaodao.com/Api/"
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
2.設置接口service
注意到每個endpoint 都指定了一個關于HTTP(GET, POST, 等等。) 方法的注解以及用于分發(fā)網(wǎng)絡調用的方法。而且這些方法的參數(shù)也可以有特殊的注解。
/**
* 接口地址
* Created by WZG on 2016/7/16.
*/
public interface MyApiEndpointInterface {
@POST("AppFiftyToneGraph/videoLink")
Call<RetrofitEntity> getAllVedio(@Body boolean once_no)
}
3.得到call然后同步處理處理回調:
MyApiEndpointInterface apiService = retrofit.create(MyApiEndpointInterface.class);
Call<RetrofitEntity> call = apiService.getAllVedio(true);
call.enqueue(new Callback<RetrofitEntity>() {
@Override
public void onResponse(Response<RetrofitEntity> response, Retrofit retrofit) {
RetrofitEntity entity = response.body();
Log.i("tag", "onResponse----->" + entity.getMsg());
}
@Override
public void onFailure(Throwable t) {
Log.i("tag", "onFailure----->" + t.toString());
}
});
這就是簡單的Retrofit使用步驟,接下來我們結合RxJava講述
ReTrofit+Rxjava基本使用
對比之前的Retrofit使用
1.在于我們需要修改service接口返回信息我們需要返回一個Observable對象
@POST("AppFiftyToneGraph/videoLink")
Observable<RetrofitEntity> getAllVedioBy(@Body boolean once_no);
2.然后初始化Retrofit需要添加對Rxjava的適配,注意一定要retrofit2才有這個功能哦
Retrofit retrofit = new Retrofit.Builder()
.client(builder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(HttpManager.BASE_URL)
.build();
3.回調通過RxJava處理
HttpService apiService = retrofit.create(HttpService.class);
Observable<RetrofitEntity> observable = apiService.getAllVedioBy(true);
observable.subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Subscriber<RetrofitEntity>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(RetrofitEntity retrofitEntity) {
tvMsg.setText("無封裝:\n" + retrofitEntity.getData().toString());
}
}
);
簡單的RxJava集合Retrofit的使用就介紹完了,同樣的可以發(fā)現(xiàn)使用起來很多重復性的代碼,而且使用也不是那么簡單,所以才有了下面的封裝
ReTrofit+Rxjava進階封裝之路
先來一張流程圖壓壓驚

請求數(shù)據(jù)封裝
1.參數(shù)
首先需要封裝的使我們的數(shù)據(jù)類,在數(shù)據(jù)類中需要封裝請求中用到的相關數(shù)據(jù)的設置,比如請求參數(shù)、方法、加載框顯示設置等等
public abstract class BaseApi<T> implements Func1<BaseResultEntity<T>, T> {
//rx生命周期管理
private SoftReference<RxAppCompatActivity> rxAppCompatActivity;
/*回調*/
private SoftReference<HttpOnNextListener> listener;
/*是否能取消加載框*/
private boolean cancel;
/*是否顯示加載框*/
private boolean showProgress;
/*是否需要緩存處理*/
private boolean cache;
/*基礎url*/
private String baseUrl="http://www.izaodao.com/Api/";
/*方法-如果需要緩存必須設置這個參數(shù);不需要不用設置*/
private String mothed;
/*超時時間-默認6秒*/
private int connectionTime = 6;
/*有網(wǎng)情況下的本地緩存時間默認60秒*/
private int cookieNetWorkTime=60;
/*無網(wǎng)絡的情況下本地緩存時間默認30天*/
private int cookieNoNetWorkTime=24*60*60*30;
}
注釋很詳細,這里不具體描述了,由于這里是最后封裝完成以后的代碼,所以有些內容本章還會部分不會涉及,因為功能太多,還是按照一開始的博客章節(jié)講解。
2.抽象api接口
/** * 設置參數(shù) * * @param retrofit * @return */ public abstract Observable getObservable(Retrofit retrofit);
通過子類也即是我們的具體api接口,通過getObservable實現(xiàn)service中定義的接口方法,例如:
public class SubjectPostApi extends BaseApi {
xxxxxxx
xxxxxxx
@Override
public Observable getObservable(Retrofit retrofit) {
HttpPostService service = retrofit.create(HttpPostService.class);
return service.getAllVedioBys(isAll());
}
}
通過傳入的Retrofit對象,可以隨意切換挑選Service對象,得到定義的注解方法,初始完成以后返回Observable對象。
3.結果判斷
這里結合RxJava的map方法在服務器返回數(shù)據(jù)中,統(tǒng)一處理數(shù)據(jù)處理,所以BaseApi<T> implements
Func1<BaseResultEntity<T>, T>,后邊結合結果處理鏈接起來使用
@Override
public T call(BaseResultEntity<T> httpResult) {
if (httpResult.getRet() == 0) {
throw new HttpTimeException(httpResult.getMsg());
}
return httpResult.getData();
}
由于測試接口,也是當前我們公司接口都是有統(tǒng)一規(guī)則的,想必大家都有這樣的接口規(guī)則,所以才有這里的統(tǒng)一判斷,規(guī)則如下:
* ret:1成功,2失敗
* msg:信息
* data:{
* name:視頻名稱
* title:標題
* }
其實上面的接口文檔中就介紹了,統(tǒng)一先通過ret判斷,失敗顯示msg信息,data是成功后的數(shù)據(jù)也就是用戶關心的數(shù)據(jù),所以可封裝一個結果對象BaseResultEntity.
4.結果數(shù)據(jù)
/**
* 回調信息統(tǒng)一封裝類
* Created by WZG on 2016/7/16.
*/
public class BaseResultEntity<T> {
// 判斷標示
private int ret;
// 提示信息
private String msg;
//顯示數(shù)據(jù)(用戶需要關心的數(shù)據(jù))
private T data;
xxxxx get-set xxxxx
}
這里結合BaseApi的Func1判斷,失敗直接拋出一個異常,交個RxJava的onError處理,成功則將用戶關心的數(shù)據(jù)傳給Gson解析返回
5.泛型傳遞
BaseResultEntity<T>中的泛型T也就是我們所關心的回調數(shù)據(jù),同樣也是Gson最后解析返回的數(shù)據(jù),傳遞的過程根節(jié)點是通過定義service方法是給定的,例如:
public interface HttpPostService {
@POST("AppFiftyToneGraph/videoLink")
Call<RetrofitEntity> getAllVedio(@Body boolean once_no);
}
其中的RetrofitEntity就是用戶關心的數(shù)據(jù)類,通過泛型傳遞給最后的接口。
6.強調
很多兄弟通過QQ群反饋給我說,使用一個接口需要寫一個對應的api類繼承BaseApi是不是很麻煩,我這里強調一下,這樣封裝是為了將一個Api接口作為一個對象去封裝,個人覺得有必要封裝成一個類,在日后工程日益增加接口隨著增加的同時,對象的做法更加有利于查找接口和修改接口有利于迭代。
操作類封裝
1初始對象
首先初始化一個單利方便HttpManager請求;這里用了volatile的對象
private volatile static HttpManager INSTANCE;
//構造方法私有
private HttpManager() {
}
//獲取單例
public static HttpManager getInstance() {
if (INSTANCE == null) {
synchronized (HttpManager.class) {
if (INSTANCE == null) {
INSTANCE = new HttpManager();
}
}
}
return INSTANCE;
}
2接口處理和回調處理:
/**
* 處理http請求
*
* @param basePar 封裝的請求數(shù)據(jù)
*/
public void doHttpDeal(BaseApi basePar) {
//手動創(chuàng)建一個OkHttpClient并設置超時時間緩存等設置
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(basePar.getConnectionTime(), TimeUnit.SECONDS);
builder.addInterceptor(new CookieInterceptor(basePar.isCache()));
/*創(chuàng)建retrofit對象*/
Retrofit retrofit = new Retrofit.Builder()
.client(builder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(basePar.getBaseUrl())
.build();
/*rx處理*/
ProgressSubscriber subscriber = new ProgressSubscriber(basePar);
Observable observable = basePar.getObservable(retrofit)
/*失敗后的retry配置*/
.retryWhen(new RetryWhenNetworkException())
/*生命周期管理*/
.compose(basePar.getRxAppCompatActivity().bindToLifecycle())
/*http請求線程*/
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
/*回調線程*/
.observeOn(AndroidSchedulers.mainThread())
/*結果判斷*/
.map(basePar);
/*數(shù)據(jù)回調*/
observable.subscribe(subscriber);
}
首先通過api接口類BaseApi的實現(xiàn)類中數(shù)據(jù)初始化OkHttpClient和Retrofit對象,其中包含了url,超時等,接著通過BaseApi的抽象方法getObservable得到Observable對象,得到Observable對象以后,我們就能隨意的切換現(xiàn)成來處理,整個請求通過compose設定的rxlifecycle來管理生命周期,所以不會溢出和泄露無需任何擔心,最后再服務器數(shù)據(jù)返回時,通過map判斷結果,剔除錯誤信息,成功以后返回到自定義的ProgressSubscriber對象中,所以接下來封裝ProgressSubscriber對象。
ProgressSubscriber封裝
ProgressSubscriber其實是繼承于Subscriber,封裝的方法無非是對Subscriber的回調方法的封裝
- onStart():開始
- onCompleted():結束
- onError(Throwable e):錯誤
- onNext(T t):成功
1.請求加載框
http請求都伴隨著加載框的使用,所以這里需要在onStart()使用前初始一個加載框,這里簡單的用ProgressDialog代替
/**
* 用于在Http請求開始時,自動顯示一個ProgressDialog
* 在Http請求結束是,關閉ProgressDialog
* 調用者自己對請求數(shù)據(jù)進行處理
* Created by WZG on 2016/7/16.
*/
public class ProgressSubscriber<T> extends Subscriber<T> {
/*是否彈框*/
private boolean showPorgress = true;
/* 軟引用回調接口*/
private SoftReference<HttpOnNextListener> mSubscriberOnNextListener;
/*軟引用反正內存泄露*/
private SoftReference<RxAppCompatActivity> mActivity;
/*加載框可自己定義*/
private ProgressDialog pd;
/*請求數(shù)據(jù)*/
private BaseApi api;
/**
* 構造
*
* @param api
*/
public ProgressSubscriber(BaseApi api) {
this.api = api;
this.mSubscriberOnNextListener = api.getListener();
this.mActivity = new SoftReference<>(api.getRxAppCompatActivity());
setShowPorgress(api.isShowProgress());
if (api.isShowProgress()) {
initProgressDialog(api.isCancel());
}
}
/**
* 初始化加載框
*/
private void initProgressDialog(boolean cancel) {
Context context = mActivity.get();
if (pd == null && context != null) {
pd = new ProgressDialog(context);
pd.setCancelable(cancel);
if (cancel) {
pd.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
onCancelProgress();
}
});
}
}
}
/**
* 顯示加載框
*/
private void showProgressDialog() {
if (!isShowPorgress()) return;
Context context = mActivity.get();
if (pd == null || context == null) return;
if (!pd.isShowing()) {
pd.show();
}
}
/**
* 隱藏
*/
private void dismissProgressDialog() {
if (!isShowPorgress()) return;
if (pd != null && pd.isShowing()) {
pd.dismiss();
}
}
}
由于progress的特殊性,需要指定content而且不能是Application所以這里傳遞一個RxAppCompatActivity,而同時上面的HttpManager同樣需要,所以這里統(tǒng)一還是按照BaseApi傳遞過來,使用軟引用的方式避免泄露。剩下的無非是初始化,顯示和關閉方法,可以詳細看代碼。
2.onStart()實現(xiàn)
在onStart()中需要調用加載框,然后這里還有網(wǎng)絡緩存的邏輯,后面會單獨講解,現(xiàn)在先忽略它的存在。
/**
* 訂閱開始時調用
* 顯示ProgressDialog
*/
@Override
public void onStart() {
showProgressDialog();
/*緩存并且有網(wǎng)*/
if (api.isCache() && AppUtil.isNetworkAvailable(RxRetrofitApp.getApplication())) {
/*獲取緩存數(shù)據(jù)*/
CookieResulte cookieResulte = CookieDbUtil.getInstance().queryCookieBy(api.getUrl());
if (cookieResulte != null) {
long time = (System.currentTimeMillis() - cookieResulte.getTime()) / 1000;
if (time < api.getCookieNetWorkTime()) {
if (mSubscriberOnNextListener.get() != null) {
mSubscriberOnNextListener.get().onCacheNext(cookieResulte.getResulte());
}
onCompleted();
unsubscribe();
}
}
}
}
3.onCompleted()實現(xiàn)
/**
* 完成,隱藏ProgressDialog
*/
@Override
public void onCompleted() {
dismissProgressDialog();
}
4.onError(Throwable e)實現(xiàn)
在onError(Throwable e)是對錯誤信息的處理和緩存讀取的處理,后續(xù)會講解,先忽略。
/**
* 對錯誤進行統(tǒng)一處理
* 隱藏ProgressDialog
*
* @param e
*/
@Override
public void onError(Throwable e) {
dismissProgressDialog();
/*需要緩存并且本地有緩存才返回*/
if (api.isCache()) {
Observable.just(api.getUrl()).subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
errorDo(e);
}
@Override
public void onNext(String s) {
/*獲取緩存數(shù)據(jù)*/
CookieResulte cookieResulte = CookieDbUtil.getInstance().queryCookieBy(s);
if (cookieResulte == null) {
throw new HttpTimeException("網(wǎng)絡錯誤");
}
long time = (System.currentTimeMillis() - cookieResulte.getTime()) / 1000;
if (time < api.getCookieNoNetWorkTime()) {
if (mSubscriberOnNextListener.get() != null) {
mSubscriberOnNextListener.get().onCacheNext(cookieResulte.getResulte());
}
} else {
CookieDbUtil.getInstance().deleteCookie(cookieResulte);
throw new HttpTimeException("網(wǎng)絡錯誤");
}
}
});
} else {
errorDo(e);
}
}
/*錯誤統(tǒng)一處理*/
private void errorDo(Throwable e) {
Context context = mActivity.get();
if (context == null) return;
if (e instanceof SocketTimeoutException) {
Toast.makeText(context, "網(wǎng)絡中斷,請檢查您的網(wǎng)絡狀態(tài)", Toast.LENGTH_SHORT).show();
} else if (e instanceof ConnectException) {
Toast.makeText(context, "網(wǎng)絡中斷,請檢查您的網(wǎng)絡狀態(tài)", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "錯誤" + e.getMessage(), Toast.LENGTH_SHORT).show();
}
if (mSubscriberOnNextListener.get() != null) {
mSubscriberOnNextListener.get().onError(e);
}
}
5.onNext(T t)實現(xiàn)
/**
* 將onNext方法中的返回結果交給Activity或Fragment自己處理
*
* @param t 創(chuàng)建Subscriber時的泛型類型
*/
@Override
public void onNext(T t) {
if (mSubscriberOnNextListener.get() != null) {
mSubscriberOnNextListener.get().onNext(t);
}
}
主要是是將得到的結果,通過自定義的接口返回給view界面,其中的軟引用對象mSubscriberOnNextListener是自定義的接口回調類HttpOnNextListener.
6.HttpOnNextListener封裝
現(xiàn)在只需關心onNext(T t)和onError(Throwable e)接口即可,回調的觸發(fā)點都是在上面的ProgressSubscriber中調用
/**
* 成功回調處理
* Created by WZG on 2016/7/16.
*/
public abstract class HttpOnNextListener<T> {
/**
* 成功后回調方法
* @param t
*/
public abstract void onNext(T t);
/**
* 緩存回調結果
* @param string
*/
public void onCacheNext(String string){
}
/**
* 失敗或者錯誤方法
* 主動調用,更加靈活
* @param e
*/
public void onError(Throwable e){
}
/**
* 取消回調
*/
public void onCancel(){
}
}
失敗后的retry處理
這里你可能會問,Retrofit有自帶的retry處理呀,的確Retrofit有自帶的retry處理,但是有很多的局限,先看下使用
OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.retryOnConnectionFailure(true);
使用起來還是很方便,只需要調用一個方法即可,但是它是不可控的,也就是沒有辦法設置retry時間次數(shù),所以不太靈活,既然如此還不如自己封裝一下,因為用RxJava實現(xiàn)這個簡直小菜,無形中好像已經(jīng)給RxJava打了廣告,中毒太深。
很簡單直接上代碼:
/**
* retry條件
* Created by WZG on 2016/10/17.
*/
public class RetryWhenNetworkException implements Func1<Observable<? extends Throwable>, Observable<?>> {
// retry次數(shù)
private int count = 3;
// 延遲
private long delay = 3000;
// 疊加延遲
private long increaseDelay = 3000;
public RetryWhenNetworkException() {
}
public RetryWhenNetworkException(int count, long delay) {
this.count = count;
this.delay = delay;
}
public RetryWhenNetworkException(int count, long delay, long increaseDelay) {
this.count = count;
this.delay = delay;
this.increaseDelay = increaseDelay;
}
@Override
public Observable<?> call(Observable<? extends Throwable> observable) {
return observable
.zipWith(Observable.range(1, count + 1), new Func2<Throwable, Integer, Wrapper>() {
@Override
public Wrapper call(Throwable throwable, Integer integer) {
return new Wrapper(throwable, integer);
}
}).flatMap(new Func1<Wrapper, Observable<?>>() {
@Override
public Observable<?> call(Wrapper wrapper) {
if ((wrapper.throwable instanceof ConnectException
|| wrapper.throwable instanceof SocketTimeoutException
|| wrapper.throwable instanceof TimeoutException)
&& wrapper.index < count + 1) { //如果超出重試次數(shù)也拋出錯誤,否則默認是會進入onCompleted
return Observable.timer(delay + (wrapper.index - 1) * increaseDelay, TimeUnit.MILLISECONDS);
}
return Observable.error(wrapper.throwable);
}
});
}
private class Wrapper {
private int index;
private Throwable throwable;
public Wrapper(Throwable throwable, int index) {
this.index = index;
this.throwable = throwable;
}
}
}
使用
到這里,我們第一步封裝已經(jīng)完成了,下面講解下如何使用,已經(jīng)看明白的各位看官,估計早就看明白了使用方式,無非是創(chuàng)建一個api對象繼承BaseApi初始接口信息,然后調用HttpManager對象的doHttpDeal(BaseApi basePar)方法,最后靜靜的等待回調類HttpOnNextListener<T>類返回的onNext(T t)成功數(shù)據(jù)或者onError(Throwable e)數(shù)據(jù)。
其實代碼就是這樣:
api接口對象
/**
* 測試數(shù)據(jù)
* Created by WZG on 2016/7/16.
*/
public class SubjectPostApi extends BaseApi {
// 接口需要傳入的參數(shù) 可自定義不同類型
private boolean all;
/*任何你先要傳遞的參數(shù)*/
// String xxxxx;
/**
* 默認初始化需要給定回調和rx周期類
* 可以額外設置請求設置加載框顯示,回調等(可擴展)
* @param listener
* @param rxAppCompatActivity
*/
public SubjectPostApi(HttpOnNextListener listener, RxAppCompatActivity rxAppCompatActivity) {
super(listener,rxAppCompatActivity);
setShowProgress(true);
setCancel(true);
setCache(true);
setMothed("AppFiftyToneGraph/videoLink");
setCookieNetWorkTime(60);
setCookieNoNetWorkTime(24*60*60);
}
public boolean isAll() {
return all;
}
public void setAll(boolean all) {
this.all = all;
}
@Override
public Observable getObservable(Retrofit retrofit) {
HttpPostService service = retrofit.create(HttpPostService.class);
return service.getAllVedioBys(isAll());
}
}
請求回調
// 完美封裝簡化版
private void simpleDo() {
SubjectPostApi postEntity = new SubjectPostApi(simpleOnNextListener,this);
postEntity.setAll(true);
HttpManager manager = HttpManager.getInstance();
manager.doHttpDeal(postEntity);
}
// 回調一一對應
HttpOnNextListener simpleOnNextListener = new HttpOnNextListener<List<SubjectResulte>>() {
@Override
public void onNext(List<SubjectResulte> subjects) {
tvMsg.setText("網(wǎng)絡返回:\n" + subjects.toString());
}
@Override
public void onCacheNext(String cache) {
/*緩存回調*/
Gson gson=new Gson();
java.lang.reflect.Type type = new TypeToken<BaseResultEntity<List<SubjectResulte>>>() {}.getType();
BaseResultEntity resultEntity= gson.fromJson(cache, type);
tvMsg.setText("緩存返回:\n"+resultEntity.getData().toString() );
}
/*用戶主動調用,默認是不需要覆寫該方法*/
@Override
public void onError(Throwable e) {
super.onError(e);
tvMsg.setText("失敗:\n" + e.toString());
}
/*用戶主動調用,默認是不需要覆寫該方法*/
@Override
public void onCancel() {
super.onCancel();
tvMsg.setText("取消請求");
}
};
后續(xù)
到這里,封裝功能中很多功能還沒涉及和講解,后續(xù)會陸續(xù)更新!
先給大家看看為師的完全體功能:
1.Retrofit+Rxjava+okhttp基本使用方法
2.統(tǒng)一處理請求數(shù)據(jù)格式
3.統(tǒng)一的ProgressDialog和回調Subscriber處理
4.取消http請求
5.預處理http請求
6.返回數(shù)據(jù)的統(tǒng)一判斷
7.失敗后的retry處理
8.RxLifecycle管理生命周期,防止泄露
9.文件上傳下載(支持多文件,斷點續(xù)傳)
10.Cache數(shù)據(jù)持久化和數(shù)據(jù)庫(greenDao)兩種緩存機制
11.異常統(tǒng)一處理
來個圖壓壓驚:

源碼:
RxRetrofit-終極封裝-深入淺出&網(wǎng)絡請求-GitHub
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Android實現(xiàn)收到新短信后自動發(fā)郵件功能
這篇文章主要為大家詳細介紹了Android實現(xiàn)收到新短信后自動發(fā)郵件功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-05-05
Android系統(tǒng)的五種數(shù)據(jù)存儲形式實例(二)
Android系統(tǒng)有五種數(shù)據(jù)存儲形式,分別是文件存儲、SP存儲、數(shù)據(jù)庫存儲、contentprovider 內容提供者、網(wǎng)絡存儲。本文介紹了Android系統(tǒng)的五種數(shù)據(jù)存儲形式,有興趣的可以了解一下。2016-12-12
Flutter如何輕松實現(xiàn)動態(tài)更新ListView淺析
在Android中通常都會用到listview.那么flutter里面怎么用呢?下面這篇文章主要給大家介紹了關于Flutter如何輕松實現(xiàn)動態(tài)更新ListView的相關資料,需要的朋友可以參考下2022-02-02
Intent傳遞對象之Serializable和Parcelable的區(qū)別
Intent在不同的組件中傳遞對象數(shù)據(jù)的應用非常普遍,大家都知道在intent傳遞對象的方法有兩種:1、實現(xiàn)Serializable接口、2、實現(xiàn)Parcelable接口,接下來通過本文給大家介紹Intent傳遞對象之Serializable和Parcelable的區(qū)別,感興趣的朋友一起學習吧2016-01-01
Android Studio使用教程(一):下載與安裝及創(chuàng)建HelloWorld項目
這篇文章主要介紹了Android Studio使用教程(一):下載與安裝及創(chuàng)建HelloWorld項目,本文用詳細的圖文說明講解了Android Studio初步使用,需要的朋友可以參考下2015-05-05
Android中使用RecyclerView實現(xiàn)下拉刷新和上拉加載
RecyclerView 是Android L版本中新添加的一個用來取代ListView的SDK,它的靈活性與可替代性比listview更好。這篇文章主要介紹了Android中使用RecyclerView實現(xiàn)下拉刷新和上拉加載的相關資料,需要的朋友可以參考下2016-03-03

