背景:
CSDN
部落格釋出了一系列的RxJava+Retrofit+OkHttp
深入淺出-終極封裝是不是很眼熟,是的還是它,不過是不同的配方。之前發出後收到很多朋友的關注,原本只是自己學習後的一些經驗總結,但是有同學運用到實戰當中,這讓我很惶恐,所有後續一直更新了很多次版本,有些地方難免有所變動導致之前的部落格有所出入,正好最近受到掘金邀請內測部落格,所以決定重新寫一版,按照最後迭代完成的封裝詳細的講述一遍,歡迎大家關注!
注意:由於本章的特殊性,後續文章比較長而且複雜,涉及內容也很多,所以大家準備好茶水,前方高能預警。
封裝成果
封裝完以後,具有如下功能:
1.Retrofit+Rxjava+okhttp基本使用方法
2.統一處理請求資料格式
3.統一的ProgressDialog和回撥Subscriber處理
4.取消http請求
5.預處理http請求
6.返回資料的統一判斷
7.失敗後的retry封裝處理
8.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(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();
}
}
);
}複製程式碼
可能你發現確是程式碼有點多,但是更加可怕的是,如果你一個activity或者fragment中多次需要http請求,你需要多次重複的寫回撥處理(一個回到就有4個方法呀!!!!反正我是忍受不了),而且以上處理還沒有做過多的判斷和錯誤校驗就如此複雜!~好了介紹完了,開始我們們的優化之路吧!
專案結構:
RxJava
如果你對RxJava
不瞭解,好吧騷年趕快學學吧,不然真會out
了,下面給出博主當初學習RxJava
的一些資源:
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
基本使用:
首先給定一個測試介面文件,後面的部落格中我們都是用這個介面除錯
/**
* @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
注意到每個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
然後同步處理處理回撥:
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
的使用就介紹完了,同樣的可以發現使用起來很多重複性的程式碼,而且使用也不是那麼簡單,所以才有了下面的封裝
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 = 6;
/*有網情況下的本地快取時間預設60秒*/
private int cookieNetWorkTime=60;
/*無網路的情況下本地快取時間預設30天*/
private int cookieNoNetWorkTime=24*60*60*30;
}複製程式碼
註釋很詳細,這裡不具體描述了,由於這裡是最後封裝完成以後的程式碼,所以有些內容本章還會部分不會涉及,因為功能太多,還是按照一開始的部落格章節講解。
2.抽象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() == 0) {
throw new HttpTimeException(httpResult.getMsg());
}
return httpResult.getData();
}複製程式碼
由於測試介面,也是當前我們公司介面都是有統一規則的,想必大家都有這樣的介面規則,所以才有這裡的統一判斷,規則如下:
* ret:1成功,2失敗
* 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
其實是繼承於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()
中需要呼叫載入框,然後這裡還有網路快取的邏輯,後面會單獨講解,現在先忽略它的存在。
/**
* 訂閱開始時呼叫
* 顯示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()) / 1000;
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()) / 1000;
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方法中的返回結果交給Activity或Fragment自己處理
*
* @param t 建立Subscriber時的泛型型別
*/
@Override
public void onNext(T t) {
if (mSubscriberOnNextListener.get() != null) {
mSubscriberOnNextListener.get().onNext(t);
}
}複製程式碼
主要是是將得到的結果,通過自定義的介面返回給view
介面,其中的軟引用物件mSubscriberOnNextListener
是自定義的介面回撥類HttpOnNextListener
.
6.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
處理
這裡你可能會問,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 = 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) { //如果超出重試次數也丟擲錯誤,否則預設是會進入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;
}
}
}複製程式碼
使用
到這裡,我們第一步封裝已經完成了,下面講解下如何使用,已經看明白的各位看官,估計早就看明白了使用方式,無非是建立一個api
物件繼承BaseApi
初始介面資訊,然後呼叫HttpManager
物件的doHttpDeal(BaseApi basePar)
方法,最後靜靜的等待回撥類HttpOnNextListener<T>
類返回的onNext(T t)
成功資料或者onError(Throwable e)
資料。
其實程式碼就是這樣:
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(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("網路返回:\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("取消請求");
}
};複製程式碼
後續
到這裡,封裝功能中很多功能還沒涉及和講解,後續會陸續更新!
先給大家看看為師的完全體功能:
1.Retrofit+Rxjava+okhttp基本使用方法
2.統一處理請求資料格式
3.統一的ProgressDialog和回撥Subscriber處理
4.取消http請求
5.預處理http請求
6.返回資料的統一判斷
7.失敗後的retry處理
8.RxLifecycle管理生命週期,防止洩露
9.檔案上傳下載(支援多檔案,斷點續傳)
10.Cache資料持久化和資料庫(greenDao)兩種快取機制
11.異常統一處理複製程式碼
來個圖壓壓驚:
迫不及待的小夥伴可以看這裡:
但是其中有些後續優化迭代未及時更新,別生氣,我馬上補!
原始碼:
建議
這篇文章參加掘金技術徵文:gold.xitu.io/post/58522d…