背景:
CSDN
部落格釋出了一系列的
RxJava+Retrofit+OkHttp
深入淺出-終極封裝 之前發出後收到很多朋友的關注,原本隻是自己學習後的一些經驗總結,但是有同學運用到實戰當中,這讓我很惶恐,所有後續一直更新了很多次版本,有些地方難免有所變動導緻之前的部落格有所出入,正好最近受到掘金邀請内測部落格,是以決定重新寫一版,按照最後疊代完成的封裝詳細的講述一遍,歡迎大家關注!
注意:由于本章的特殊性,後續文章比較長而且複雜,涉及内容也很多,是以大家準備好茶水,前方高能預警。
+
RxJava
+
Retrofit
深入淺出-終極封裝
OkHttp
封裝成果
封裝完以後,具有如下功能:
.Retrofit+Rxjava+okhttp基本使用方法
.統一處理請求資料格式
.統一的ProgressDialog和回調Subscriber處理
.取消http請求
.預處理http請求
.傳回資料的統一判斷
.失敗後的retry封裝處理
.RxLifecycle管理生命周期,防止洩露
實作效果:
具體使用
封裝後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實作http請求
*/
private void onButton9Click() {
//手動建立一個OkHttpClient并設定逾時時間
okhttp3.OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(, 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();
}
}
);
}
可能你發現确是代碼有點多,但是更加可怕的是,如果你一個activity或者fragment中多次需要http請求,你需要多次重複的寫回調處理(一個回到就有4個方法呀!!!!反正我是忍受不了),而且以上處理還沒有做過多的判斷和錯誤校驗就如此複雜!~好了介紹完了,開始咱們的優化之路吧!
項目結構:
RxJava
RxJava
如果你對
RxJava
不了解,好吧騷年趕快學學吧,不然真會
out
了,下面給出部落客當初學習
RxJava
的一些資源:
- 扔物線的金典RxJava
- RxJava進階一
- RxJava進階二
- RxJava進階三
- RxJava進階四
Retrofit
Retrofit
咱家今天的主角來了,咱們也深入淺出一下了解下
Retrofit
使用,前方高能,如果你是深度
Retrofit
選手請直接跳過本節!!!
1.首先確定在AndroidManifest.xml中請求了網絡權限
<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
-
:用于@Field
方式傳遞參數,需要在請求接口方法上添加Post
,即以表單的方式傳遞參數@FormUrlEncoded
-
:用于@Body
,根據轉換方式将執行個體對象轉化為對應字元串傳遞參數.比如Post
添加Retrofit
則是将GsonConverterFactory
轉化為body
字元串進行傳遞gson
-
:用于@Path
上占位符URL
-
:配合@Part
使用,一般用于檔案上傳@Multipart
-
:添加@Header
http header
-
:跟@Headers
作用一樣,隻是使用方式不一樣,@Header
是作為請求方法的參數傳入,@Header
是以固定方式直接添加到請求方法上@Headers
ReTrofit
基本使用:
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發送我們的網絡請求 ,我們需要使用
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
service
注意到每個
endpoint
都指定了一個關于
HTTP
(
GET
,
POST
, 等等。) 方法的注解以及用于分發網絡調用的方法。而且這些方法的參數也可以有特殊的注解。
/**
* 接口位址
* Created by WZG on 2016/7/16.
*/
public interface MyApiEndpointInterface {
@POST("AppFiftyToneGraph/videoLink")
Call<RetrofitEntity> getAllVedio(@Body boolean once_no)
}
3.得到 call
然後同步處理處理回調:
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+Rxjava
對比之前的
Retrofit
使用
1.在于我們需要修改 service
接口傳回資訊我們需要傳回一個 Observable
對象
service
Observable
@POST("AppFiftyToneGraph/videoLink")
Observable<RetrofitEntity> getAllVedioBy(@Body boolean once_no);
2.然後初始化 Retrofit
需要添加對 Rxjava
的适配,注意一定要 retrofit2
才有這個功能哦
Retrofit
Rxjava
retrofit2
Retrofit retrofit = new Retrofit.Builder()
.client(builder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(HttpManager.BASE_URL)
.build();
3.回調通過 RxJava
處理
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
的使用就介紹完了,同樣的可以發現使用起來很多重複性的代碼,而且使用也不是那麼簡單,是以才有了下面的封裝
ReTrofit+Rxjava進階封裝之路
先來一張流程圖壓壓驚
請求資料封裝
1.參數
首先需要封裝的使我們的資料類,在資料類中需要封裝請求中用到的相關資料的設定,比如請求參數、方法、加載框顯示設定等等
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/";
/*方法-如果需要緩存必須設定這個參數;不需要不用設置*/
private String mothed;
/*逾時時間-預設6秒*/
private int connectionTime = ;
/*有網情況下的本地緩存時間預設60秒*/
private int cookieNetWorkTime=;
/*無網絡的情況下本地緩存時間預設30天*/
private int cookieNoNetWorkTime=***;
}
注釋很詳細,這裡不具體描述了,由于這裡是最後封裝完成以後的代碼,是以有些内容本章還會部分不會涉及,因為功能太多,還是按照一開始的部落格章節講解。
2.抽象 api
接口
api
/**
* 設定參數
*
* @param retrofit
* @return
*/
public abstract Observable getObservable(Retrofit retrofit);
通過子類也即是我們的具體
api
接口,通過
getObservable
實作
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
方法在伺服器傳回資料中,統一處理資料處理,是以
BaseApi<T> implements Func1<BaseResultEntity<T>, T>
,後邊結合結果處理連結起來使用
@Override
public T call(BaseResultEntity<T> httpResult) {
if (httpResult.getRet() == ) {
throw new HttpTimeException(httpResult.getMsg());
}
return httpResult.getData();
}
由于測試接口,也是目前我們公司接口都是有統一規則的,想必大家都有這樣的接口規則,是以才有這裡的統一判斷,規則如下:
* ret:成功,失敗
* msg:資訊
* data:{
* name:視訊名稱
* title:标題
* }
其實上面的接口文檔中就介紹了,統一先通過
ret
判斷,失敗顯示
msg
資訊,
data
是成功後的資料也就是使用者關心的資料,是以可封裝一個結果對象
BaseResultEntity
.
4.結果資料
/**
* 回調資訊統一封裝類
* Created by WZG on 2016/7/16.
*/
public class BaseResultEntity<T> {
// 判斷标示
private int ret;
// 提示資訊
private String msg;
//顯示資料(使用者需要關心的資料)
private T data;
xxxxx get-set xxxxx
}
這裡結合
BaseApi
的
Func1
判斷,失敗直接抛出一個異常,交個
RxJava
的
onError
處理,成功則将使用者關心的資料傳給
Gson
解析傳回
5.泛型傳遞
BaseResultEntity<T>
中的泛型
T
也就是我們所關心的回調資料,同樣也是Gson最後解析傳回的資料,傳遞的過程根節點是通過定義
service
方法是給定的,例如:
public interface HttpPostService {
@POST("AppFiftyToneGraph/videoLink")
Call<RetrofitEntity> getAllVedio(@Body boolean once_no);
}
其中的
RetrofitEntity
就是使用者關心的資料類,通過泛型傳遞給最後的接口。
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 封裝的請求資料
*/
public void doHttpDeal(BaseApi basePar) {
//手動建立一個OkHttpClient并設定逾時時間緩存等設定
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(basePar.getConnectionTime(), TimeUnit.SECONDS);
builder.addInterceptor(new CookieInterceptor(basePar.isCache()));
/*建立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);
/*資料回調*/
observable.subscribe(subscriber);
}
首先通過
api
接口類
BaseApi
的實作類中資料初始化
OkHttpClient
和
Retrofit
對象,其中包含了
url
,逾時等,接着通過
BaseApi
的抽象方法
getObservable
得到
Observable
對象,得到
Observable
對象以後,我們就能随意的切換現成來處理,整個請求通過
compose
設定的
rxlifecycle
來管理生命周期,是以不會溢出和洩露無需任何擔心,最後再伺服器資料傳回時,通過
map
判斷結果,剔除錯誤資訊,成功以後傳回到自定義的
ProgressSubscriber
對象中,是以接下來封裝
ProgressSubscriber
對象。
ProgressSubscriber
封裝
ProgressSubscriber
ProgressSubscriber
其實是繼承于
Subscriber
,封裝的方法無非是對
Subscriber
的回調方法的封裝
- onStart():開始
- onCompleted():結束
- onError(Throwable e):錯誤
- onNext(T t):成功
1.請求加載框
http
請求都伴随着加載框的使用,是以這裡需要在
onStart()
使用前初始一個加載框,這裡簡單的用
ProgressDialog
代替
/**
* 用于在Http請求開始時,自動顯示一個ProgressDialog
* 在Http請求結束是,關閉ProgressDialog
* 調用者自己對請求資料進行處理
* 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;
/*請求資料*/
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
同樣需要,是以這裡統一還是按照
BaseApi
傳遞過來,使用軟引用的方式避免洩露。剩下的無非是初始化,顯示和關閉方法,可以詳細看代碼。
2. onStart()
實作
onStart()
在
onStart()
中需要調用加載框,然後這裡還有網絡緩存的邏輯,後面會單獨講解,現在先忽略它的存在。
/**
* 訂閱開始時調用
* 顯示ProgressDialog
*/
@Override
public void onStart() {
showProgressDialog();
/*緩存并且有網*/
if (api.isCache() && AppUtil.isNetworkAvailable(RxRetrofitApp.getApplication())) {
/*擷取緩存資料*/
CookieResulte cookieResulte = CookieDbUtil.getInstance().queryCookieBy(api.getUrl());
if (cookieResulte != null) {
long time = (System.currentTimeMillis() - cookieResulte.getTime()) / ;
if (time < api.getCookieNetWorkTime()) {
if (mSubscriberOnNextListener.get() != null) {
mSubscriberOnNextListener.get().onCacheNext(cookieResulte.getResulte());
}
onCompleted();
unsubscribe();
}
}
}
}
3.onCompleted()實作
/**
* 完成,隐藏ProgressDialog
*/
@Override
public void onCompleted() {
dismissProgressDialog();
}
4.onError(Throwable e)實作
在
onError(Throwable e)
是對錯誤資訊的處理和緩存讀取的處理,後續會講解,先忽略。
/**
* 對錯誤進行統一處理
* 隐藏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) {
/*擷取緩存資料*/
CookieResulte cookieResulte = CookieDbUtil.getInstance().queryCookieBy(s);
if (cookieResulte == null) {
throw new HttpTimeException("網絡錯誤");
}
long time = (System.currentTimeMillis() - cookieResulte.getTime()) / ;
if (time < api.getCookieNoNetWorkTime()) {
if (mSubscriberOnNextListener.get() != null) {
mSubscriberOnNextListener.get().onCacheNext(cookieResulte.getResulte());
}
} else {
CookieDbUtil.getInstance().deleteCookie(cookieResulte);
throw new HttpTimeException("網絡錯誤");
}
}
});
} else {
errorDo(e);
}
}
/*錯誤統一處理*/
private void errorDo(Throwable e) {
Context context = mActivity.get();
if (context == null) return;
if (e instanceof SocketTimeoutException) {
Toast.makeText(context, "網絡中斷,請檢查您的網絡狀态", Toast.LENGTH_SHORT).show();
} else if (e instanceof ConnectException) {
Toast.makeText(context, "網絡中斷,請檢查您的網絡狀态", 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)
實作
onNext(T t)
/**
* 将onNext方法中的傳回結果交給Activity或Fragment自己處理
*
* @param t 建立Subscriber時的泛型類型
*/
@Override
public void onNext(T t) {
if (mSubscriberOnNextListener.get() != null) {
mSubscriberOnNextListener.get().onNext(t);
}
}
主要是是将得到的結果,通過自定義的接口傳回給
view
界面,其中的軟引用對象
mSubscriberOnNextListener
是自定義的接口回調類
HttpOnNextListener
.
6. HttpOnNextListener
封裝
HttpOnNextListener
現在隻需關心
onNext(T t)
和
onError(Throwable e)
接口即可,回調的觸發點都是在上面的
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
處理
retry
這裡你可能會問,
Retrofit
有自帶的
retry
處理呀,的确
Retrofit
有自帶的
retry
處理,但是有很多的局限,先看下使用
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.retryOnConnectionFailure(true);
使用起來還是很友善,隻需要調用一個方法即可,但是它是不可控的,也就是沒有辦法設定
retry
時間次數,是以不太靈活,既然如此還不如自己封裝一下,因為用
RxJava
實作這個簡直小菜,無形中好像已經給
RxJava
打了廣告,中毒太深。
很簡單直接上代碼:
/**
* retry條件
* Created by WZG on 2016/10/17.
*/
public class RetryWhenNetworkException implements Func1<Observable<? extends Throwable>, Observable<?>> {
// retry次數
private int count = ;
// 延遲
private long delay = ;
// 疊加延遲
private long increaseDelay = ;
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(, count + ), 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 + ) { //如果超出重試次數也抛出錯誤,否則預設是會進入onCompleted
return Observable.timer(delay + (wrapper.index - ) * 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;
}
}
}
使用
到這裡,我們第一步封裝已經完成了,下面講解下如何使用,已經看明白的各位看官,估計早就看明白了使用方式,無非是建立一個
api
對象繼承
BaseApi
初始接口資訊,然後調用
HttpManager
對象的
doHttpDeal(BaseApi basePar)
方法,最後靜靜的等待回調類
HttpOnNextListener<T>
類傳回的
onNext(T t)
成功資料或者
onError(Throwable e)
資料。
其實代碼就是這樣:
api
接口對象
api
/**
* 測試資料
* Created by WZG on 2016/7/16.
*/
public class SubjectPostApi extends BaseApi {
// 接口需要傳入的參數 可自定義不同類型
private boolean all;
/*任何你先要傳遞的參數*/
// 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();
setCookieNoNetWorkTime(**);
}
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("網絡傳回:\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("取消請求");
}
};
後續
到這裡,封裝功能中很多功能還沒涉及和講解,後續會陸續更新!
先給大家看看為師的完全體功能:
.Retrofit+Rxjava+okhttp基本使用方法
.統一處理請求資料格式
.統一的ProgressDialog和回調Subscriber處理
.取消http請求
.預處理http請求
.傳回資料的統一判斷
.失敗後的retry處理
.RxLifecycle管理生命周期,防止洩露
.檔案上傳下載下傳(支援多檔案,斷點續傳)
.Cache資料持久化和資料庫(greenDao)兩種緩存機制
.異常統一處理
來個圖壓壓驚:
迫不及待的小夥伴可以看這裡:
原+
RxJava
+
Retrofit
深入淺出-終極封裝
OkHttp
但是其中有些後續優化疊代未及時更新,别生氣,我馬上補!
源碼:
RxRetrofit-終極封裝-深入淺出&網絡請求-GitHub
其實我還有一個兄弟版本-傳送門
我不會告訴你其實我還有個更加簡單的版本
建議
如果你對這套封裝有任何的問題和建議歡迎加入QQ群告訴我