本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家釋出
前言
之前在github開源過一個網路庫RxEasyHttp,這是一款基於RxJava2+Retrofit2實現簡單易用的網路請求框架。在這裡對網路庫的用法就不做過多介紹,感興趣的可以去了解下。在使用過程中一些網友反饋不知道怎麼結合Rxjava2來實現一些場景需求,希望能夠寫一遍文章介紹下。終於抽出時間來對與Rxjava2在實際場景使用的一些案例做個簡單的總結和介紹。不知道怎麼使用,主要是對RxEasyHttp有個誤區,RxEasyHttp不僅是支援採用鏈式呼叫一點到底方便使用,同時也支援返回Observable
的用法,拿到了Observable
自然就可以很好的利用Rxjava操作符了來實現各種強大的功能。本文主要是講RxEasyHttp與Rxjava2怎麼結合的,也不會Rxjava2的操作符深入講解,不然就脫離了本文的重心!廢話不多說了,一起來看看是如何使用的。
場景介紹
場景一:延遲請求
在頁面網路介面請求中,不是希望立馬請求,而是需要延遲指定的時間後再去請求。
延遲請求:利用RxJava的timer
操作符。
timer:主要作用就是建立一個Observable
,它在一個給定的延遲後發射一個特殊的值,只是延遲傳送一次並不會按照週期執行。
timer()
原始碼如下:
public static Observable<Long> timer(long delay, TimeUnit unit) {
return timer(delay, unit, Schedulers.computation());
}
複製程式碼
可以看到採用timer()
返回的是Observable<Long>
,而網路請求返回的Observable
並不是Observable<Long>
,如何將這兩個Observable
關聯起來,就需要採用另外一個操作符flatMap()
,簡單理解就是flatMap
使用一個指定的函式對原始Observable發射的每一項資料進行相應的變換操作。flatMap詳細作用不做過多介紹。
例如:延遲5秒請求
//延遲5s請求
Observable.timer(5, TimeUnit.SECONDS).flatMap(new Function<Long, ObservableSource<SkinTestResult>>() {
@Override
public ObservableSource<SkinTestResult> apply(@NonNull Long aLong) throws Exception {
//延遲結束開始執行網路請求
Observable<SkinTestResult> observable = EasyHttp.get("/v1/app/chairdressing/skinAnalyzePower/skinTestResult")
.timeStamp(true)
.execute(SkinTestResult.class);
return observable;
}
}).subscribe(new BaseSubscriber<SkinTestResult>() {
@Override
protected void onStart() {
}
@Override
public void onError(ApiException e) {
showToast(e.getMessage());
}
@Override
public void onNext(@NonNull SkinTestResult skinTestResult) {
Log.i("test", "=====" + skinTestResult.toString());
}
});
//在不需要輪詢的時候,取消輪詢
//EasyHttp.cancelSubscription(polldisposable);
複製程式碼
- timer在這裡作用延遲5s結束時就會觸發網路請求
- flatMap在這裡的作用就是將
timer
操作符返回的Observable<Long>
和網路請求的Observable<SkinTestResult>
做轉換,在subscribe訂閱時返回的內容,我們真正需要的SkinTestResult,而不是Long. 因此將Observable<Long>
變換成Observable<SkinTestResult>
輸出SkinTestResult,完美達到目的。
場景二:輪詢請求-無限輪詢
在專案中需要用到每隔5s重新整理一次頁面或者拉取最新訊息。輪詢器大家一定不陌生,開發中無論是Java的Timer+TimeTask , 還是Android的Hanlder都可實現,現在介紹另一種簡單的實現方式。
無限輪詢:利用RxJava的Interval
操作符。
interval:建立一個按固定時間間隔發射整數序列的Observable,它是按照週期執行的。原始碼如下(只展示相關的兩個方法):
public static Observable<Long> interval(long initialDelay, long period, TimeUnit unit) {
return interval(initialDelay, period, unit, Schedulers.computation());
}
public static Observable<Long> interval(long period, TimeUnit unit) {
return interval(period, period, unit, Schedulers.computation());
}
複製程式碼
可以看到採用interval()
返回的是Observable<Long>
,而網路請求返回的Observable
並不是Observable<Long>
,如何將這兩個Observable
關聯起來,就需要採用另外一個操作符flatMap()
,簡單理解就是flatMap使用一個指定的函式對原始Observable發射的每一項資料之行相應的變換操作。flatMap詳細作用不做過多介紹(同上場景一)。
例如:間隔5s輪詢一次
//自己根據需要選擇合適的interval方法
Disposable polldisposable = Observable.interval(0, 5, TimeUnit.SECONDS).flatMap(new Function<Long, ObservableSource<Content>>() {
@Override
public ObservableSource<Content> apply(@NonNull Long aLong) throws Exception {
return EasyHttp.get("/ajax.php")
.baseUrl("http://fy.iciba.com")
.params("a", "fy")
.params("f", "auto")
.params("t", "auto")
.params("w", "hello world")
//採用代理
.execute(new CallClazzProxy<TestApiResult6<Content>, Content>(Content.class) {
});
}
}).subscribeWith(new BaseSubscriber<Content>() {
@Override
public void onError(ApiException e) {
showToast(e.getMessage());
}
@Override
public void onNext(@NonNull Content content) {
showToast(content.toString());
}
});
//在不需要輪詢的時候,取消輪詢
//EasyHttp.cancelSubscription(polldisposable);
複製程式碼
- interval在這裡作用每隔5s結束時就會觸發網路請求
- 注意
interval(0, 5, TimeUnit.SECONDS)
和interval(5, TimeUnit.SECONDS)
的區別,自己根據需要選擇合適的interval方法。interval(0,5, TimeUnit.SECONDS)
:3個引數,第一個參數列示初始化延時多久開始請求,這裡用0表示不延時直接請求,第二個參數列示間隔多久輪詢一次,這裡表示間隔5s,第三個表示設定的時間單位。interval(5, TimeUnit.SECONDS)
:2個引數,其中的這個5就表示,初始延時5秒開始執行請求,輪詢也是5s,第二個表示設定的時間單位,從上面提供的interval()
原始碼可以看出。flatMap
在這裡的作用就是將interval
的Observable<Long>
和網路請求的Observable<Content>
做轉換,輸出Content,而不是Long.
場景三:輪詢請求-限定次數輪詢
這個和無限輪詢用法基本一樣,只是多了輪詢的次數限制條件,不是一直無限的輪詢下去。
輪詢次數:利用RxJava的intervalRange
或者take
操作符。
intervalRange:以一個例子說明可能更清楚,intervalRange(0,3,0,5, TimeUnit.SECONDS)
表示從0開始輸出3個資料,延遲0秒執行,每隔5秒執行一次。
take:表示只取前n項。這裡用take和interval操作符聯合使用,由於一旦interval計時開始除了解綁就無法停止,使用take操作符就簡單很多了,它的意思是隻釋放前n項,過後Observable流就自動終止。
例如:只輪詢3次
int count = 3;//輪詢3次
//方式一:採用intervalRange
//Observable.intervalRange(0,count,0,5, TimeUnit.SECONDS).flatMap(new Function<Long, ObservableSource<Content>>() {
//方式一:採用take
countdisposable = Observable.interval(0, 5, TimeUnit.SECONDS).take(count).flatMap(new Function<Long, ObservableSource<Content>>() {
@Override
public ObservableSource<Content> apply(@NonNull Long aLong) throws Exception {
return EasyHttp.get("/ajax.php")
.baseUrl("http://fy.iciba.com")
.params("a", "fy")
.params("f", "auto")
.params("t", "auto")
.params("w", "hello world")
//採用代理
.execute(new CallClazzProxy<TestApiResult6<Content>, Content>(Content.class) {
});
}
}).subscribeWith(new BaseSubscriber<Content>() {
@Override
public void onError(ApiException e) {
showToast(e.getMessage());
}
@Override
public void onNext(@NonNull Content content) {
showToast(content.toString());
}
});
//在不需要輪詢的時候,取消輪詢
//EasyHttp.cancelSubscription(polldisposable);
複製程式碼
場景四:輪詢請求-條件輪詢
條件輪詢和限定次數輪詢比較像,都是起達到目的後終止輪詢。比如一個網路請求一直在輪詢執行,直到獲取到了想要的內容後就終止掉輪詢。
條件輪詢:利用RxJava的takeUntil
操作符。
takeUntil:使用一個標誌Observable是否發射資料來判斷,當標誌Observable沒有發射資料時,正常發射資料,而一旦標誌Observable發射過了資料則後面的資料都會被丟棄。
例如:輪詢請求中如果返回的內容字串中包含“示”就終止輪詢
Observable.interval(0, 5, TimeUnit.SECONDS).flatMap(new Function<Long, ObservableSource<Content>>() {
@Override
public ObservableSource<Content> apply(@NonNull Long aLong) throws Exception {
return EasyHttp.get("/ajax.php")
.baseUrl("http://fy.iciba.com")
.params("a", "fy")
.params("f", "auto")
.params("t", "auto")
.params("w", "hello world")
//採用代理
.execute(new CallClazzProxy<TestApiResult6<Content>, Content>(Content.class) {
});
}
}).takeUntil(new Predicate<Content>() {
@Override
public boolean test(@NonNull Content content) throws Exception {
//如果條件滿足,就會終止輪詢,這裡邏輯可以自己寫
//結果為true,說明滿足條件了,就不在輪詢了
return content.getOut().contains("示");
}
}).subscribeWith(new BaseSubscriber<Content>() {
@Override
public void onError(ApiException e) {
showToast(e.getMessage());
}
@Override
public void onNext(@NonNull Content content) {
showToast(content.toString());
}
});
//在不需要輪詢的時候,取消輪詢
//EasyHttp.cancelSubscription(polldisposable);
複製程式碼
場景五:輪詢請求-過濾輪詢
過濾輪詢主要是指在輪詢的過程中對訂閱的內容做過濾,不是需要的內容就不會返回給訂閱者,但是它不會中斷輪詢。過濾輪詢也可以理解成是無限輪詢加了一個過濾條件而已。
過濾輪詢:利用Rxjava的filter
操作符。
filter:是對源Observable產生的結果按照指定條件進行過濾,只有滿足條件的結果才會提交給訂閱者。
例如:返回的狀態碼如果是錯誤就不返回給訂閱者,不更新介面(只有保證每次請求成功才重新整理介面),但是會繼續輪詢請求
Disposable filterdisposable = Observable.interval(0, 5, TimeUnit.SECONDS).flatMap(new Function<Long, ObservableSource<Content>>() {
@Override
public ObservableSource<Content> apply(@NonNull Long aLong) throws Exception {
return EasyHttp.get("/ajax.php")
.baseUrl("http://fy.iciba.com")
.params("a", "fy")
.params("f", "auto")
.params("t", "auto")
.params("w", "hello world")
//採用代理
.execute(new CallClazzProxy<TestApiResult6<Content>, Content>(Content.class) {
});
}
}).filter(new Predicate<Content>() {
@Override
public boolean test(@NonNull Content content) throws Exception {
//如果不滿足條件就過濾該條輪詢資料,但是輪詢還是一直執行
//ErrNo==0表示成功,如果不等於0就認為失敗,content不會返回給訂閱者
return content.getErrNo() != 0;
}
}).subscribeWith(new BaseSubscriber<Content>() {
@Override
public void onError(ApiException e) {
showToast(e.getMessage());
}
@Override
public void onNext(@NonNull Content content) {
showToast(content.toString());
}
});
//在不需要輪詢的時候,取消輪詢
//EasyHttp.cancelSubscription(polldisposable);
複製程式碼
filter
操作符在這裡只是為了舉列說明,是自己為了講解定義了一個過濾輪詢的概念,不是說filter
只能在輪詢這裡使用,它是可以和其它任何Rxjava操作符配合使用。- 切記
takeUntil
和filter
的區別,takeUntil
找到自己想要的資料後就結束了流,不再執行任何操作。filter
發現不符合條件的不會給訂閱者,只有符合條件的才給訂閱者,發現不符合的,不會中斷操作。
場景六:巢狀請求
在開發中由於請求網路資料頻繁,往往後面一個請求的引數是前面一個請求的結果,於是經常需要在前面一個請求的響應中去傳送第二個請求,從而造成“請求巢狀”的問題。如果層次比較多,程式碼可讀性和效率都是問題。巢狀請求:利用RxJava的flatMap
操作符。
flatMap:是一個Observable的操作符,接受一個Func1閉包,這個閉包的第一個函式是待操作的上一個資料流中的資料型別,第二個是這個flatMap操作完成後返回的資料型別的被封裝的Observable。說白了就是將一個多級數列“拍扁”成了一個一級數列。
例如:網路請求獲取到token後,把token當成另一個介面的引數,一個介面依賴另一個介面。
//第一個網路請求獲取到token
Observable<AuthModel> login = EasyHttp.post(ComParamContact.Login.PATH)
.params(ComParamContact.Login.ACCOUNT, "186****4275")
.params(ComParamContact.Login.PASSWORD, MD5.encrypt4login("123456", AppConstant.APP_SECRET))
.sign(true)
.timeStamp(true).execute(AuthModel.class);
login.flatMap(new Function<AuthModel, ObservableSource<SkinTestResult>>() {
@Override
public ObservableSource<SkinTestResult> apply(@NonNull AuthModel authModel) throws Exception {
//獲取到的token,給到第二個網路當引數。第二個網路開始請求
return EasyHttp.get("/v1/app/chairdressing/skinAnalyzePower/skinTestResult")
.params("accessToken", authModel.getAccessToken())//這個地方只是舉例,並不一定是需要accessToken
.timeStamp(true)
.execute(SkinTestResult.class);
}
}).subscribe(new ProgressSubscriber<SkinTestResult>(this, mProgressDialog) {
@Override
public void onError(ApiException e) {
super.onError(e);
showToast(e.getMessage());
}
@Override
public void onNext(SkinTestResult skinTestResult) {
showToast(skinTestResult.toString());
}
});
複製程式碼
本例中只是展示了2個介面的巢狀請求,flatMap其實是可以支援巢狀很多個介面請求
場景七:合併請求(zip)
zip合併請求就是指當一個頁面有多個不同的資料來源,既就是有多個不同的網路請求介面,等待這些所有的介面都請求完成後才返回給訂閱者,重新整理介面等操作。 zip:使用一個函式組合多個Observable發射的資料集合,然後再發射這個結果. 例如:一個頁面有3個不同資料來源的網路請求介面,等待全部請求完成後才返回
Observable<ResultBean> mobileObservable = EasyHttp.get("http://apis.juhe.cn/mobile/get")
.params("phone", "18688994275")
.params("dtype", "json")
.params("key", "5682c1f44a7f486e40f9720d6c97ffe4")
.execute(new CallClazzProxy<TestApiResult1<ResultBean>, ResultBean>(ResultBean.class) {
});
Observable<Content> searchObservable = EasyHttp.get("/ajax.php")
.baseUrl("http://fy.iciba.com")
.params("a", "fy")
.params("f", "auto")
.params("t", "auto")
.params("w", "hello world")
//採用代理
.execute(new CallClazzProxy<TestApiResult6<Content>, Content>(Content.class) {
});
Observable<List<SectionItem>> listObservable = EasyHttp.get("http://news-at.zhihu.com/api/3/sections")
.execute(new CallClazzProxy<TestApiResult5<List<SectionItem>>, List<SectionItem>>(new TypeToken<List<SectionItem>>() {
}.getType()) {
});
//new Function3最後一個引數這裡用的是List<Object>,表示將3個返回的結果,放在同一個集合最終一次性返回,
你也可以指定返回其它你需要的資料型別 並不一定是List<Object>
//假如這三個介面返回的都是TestBean,那麼就可以直接用具體的List<TestBean>,不需要用List<Object>
Observable.zip(mobileObservable, searchObservable, listObservable, new Function3<ResultBean, Content, List<SectionItem>, List<Object>>() {
@Override
public List<Object> apply(@NonNull ResultBean resultbean, @NonNull Content content, @NonNull List<SectionItem> sectionItems) throws Exception {
//將接收到的3個資料先暫存起來,一次性發給訂閱者
List list = new ArrayList();
list.add(resultbean);
list.add(content);
list.add(sectionItems);
//這裡也可以進行邏輯處理,處理成你自己需要的結果後,再返回。
return list;
}
}).subscribe(new BaseSubscriber<List<Object>>() {
@Override
public void onError(ApiException e) {
showToast(e.getMessage());
}
@Override
public void onNext(@NonNull List<Object> objects) {
showToast(objects.toString());
}
});
複製程式碼
1.zip的引數中前幾個引數都表示資料來源
ObservableSource
,最後一個引數new Function會輸出結果,前面如果有2個資料來源就用Function2,3個資料來源就用Function3. 2.Function的作用主要是會返回所有參與zip的結果內容,例如本例是有3個資料來源(3個網路介面請求對應的Observable),返回的內容是new Function3<ResultBean, Content, List<SectionItem>, List<Object>>
其中ResultBean, Content, List<SectionItem>
是三個網路介面各自返回的內容。但是最後一個引數List<Object>
表示什麼呢?這一個就表示最終要給訂閱著subscribe
的內容,例如本例new BaseSubscriber<List<Object>>()
。這裡我是將返回的結果用一個List集合存起來,然後返回給訂閱者。最終想返回什麼是根據自己的業務邏輯需求而定,並不一定就是List<Object>
,切記!切記!切記!
場景八:合併請求(merge)
剛才講解了zip合併請求,這是合併請求的另一種場景實現方式merge,一定要注意merge和zip的區別,雖然都是合併多個請求,但是是有區別的,請注意使用場景. 本例中利用Rxjava的merge
、mergeDelayError
操作符。
merge:將多個Observalbe發射的資料項,合併到一個Observable中再發射出去,可能會讓合併的Observable發射的資料交錯(concat操作符是連線不會出現交錯),如果在合併的途中出現錯誤,就會立即將錯誤提交給訂閱者,將終止合併後的Observable。
mergeDelayError:mergeDelayError
操作符類似於merge
操作符,唯一不同就是如果在合併途中出現錯誤,不會立即發射錯誤通知,而是保留錯誤直到合併後的Observable將所有的資料發射完成,此時才會將onError提交給訂閱者。
例如:一個介面有兩個網路介面請求
//這個請求故意延時5秒再傳送->最後測試結果發現,並不是searchObservable等待mobileObservable5秒後再傳送,目的驗證無序的概念
Observable<ResultBean> mobileObservable = Observable.timer(5, TimeUnit.SECONDS).flatMap(new Function<Long, ObservableSource<ResultBean>>() {
@Override
public ObservableSource<ResultBean> apply(@NonNull Long aLong) throws Exception {
return EasyHttp.get("http://apis.juhe.cn/mobile/get")
.params("phone", "18688994275")
.params("dtype", "json")
.params("key", "5682c1f44a7f486e40f9720d6c97ffe4")
.execute(new CallClazzProxy<TestApiResult1<ResultBean>, ResultBean>(ResultBean.class) {
});
}
});
Observable<Content> searchObservable = EasyHttp.get("/ajax.php")
.baseUrl("http://fy.iciba.com")
.params("a", "fy")
.params("f", "auto")
.params("t", "auto")
.params("w", "hello world")
//採用代理
.execute(new CallClazzProxy<TestApiResult6<Content>, Content>(Content.class) {
});
//Observable.merge(mobileObservable,searchObservable).subscribe(new BaseSubscriber<Object>() {
Observable.mergeDelayError(mobileObservable,searchObservable).subscribe(new BaseSubscriber<Object>() {
@Override
public void onError(ApiException e) {
showToast(e.getMessage());
}
@Override
public void onNext(@NonNull Object object) {
//為什麼用Object接收,因為兩個介面請求返回的資料型別不是一樣的,如果是一樣的就用具體的物件接收就可以了,
// 不再需要instanceof麻煩的判斷
if (object instanceof ResultBean) {//mobileObservable 返回的結果
//處理 ResultBean邏輯
} else if (object instanceof Content) {
//處理 Content邏輯
}
showToast(object.toString());
}
});
複製程式碼
其中提到一個概念:合併的Observable發射的資料交錯,也就是發射的資料無序,怎麼理解它呢?例如:程式碼中merge(mobileObservable,searchObservable)
合併的mobileObservable和searchObservable,其中mobileObservable在前,並不代表訂閱的subscribe->onNext(@NonNull Object object)
就先返回來資料,也可能是合併的searchObservable資料先返回回來。
延伸講解,剛才講解了merge
操作符是無序的,如果想保證有序執行怎麼辦呢,採用Rxjava的concat
操作符
看完場景七和場景八:merge和zip的區別到底是什麼呢?
merge和zip都是將多個Observalbe發射的資料項,合併到一個Observable中再發射出去。只是在發射的結果上有所不同。例如有3個網路請求的Observalbe,zip是等待這3個請求都完成後才一起返回,既onNext呼叫1次。merge是3個Observalbe分別返回,而且無序,既onNext呼叫3次,相當於把3個本來分散的網路請求。寫在同一個地方合併起來執行。
merge、mergeDelayError都是合併,但是需要注意二者區別。
- merge合併的請求,如果有一個介面報錯了,就立馬報錯,會終止整個流,另外的介面也不會請求。
- mergeDelayError合併的請求,如果有一個介面報錯了,會延遲錯誤處理,後面的介面會繼續執行沒有被中斷。
場景九:避免重複請求
這裡主要是講解RxEasyHttp如何結合rxbinding庫compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
來使用。對rxbinding庫不瞭解的,可以自己去學習一下,這裡不詳細介紹。在頁面請求中可能操作太快導致同一個網路請求重複執行,這裡結合view來說明,點選一個按鈕去請求網路,點選太快就會重複執行-介面防抖。
避免重複請求:利用Rxjavad的throttleFirst
操作符。
throttleFirst:會定期發射這個時間段裡源Observable發射的第一個資料。
例如:點選按鈕去請求網路,1s內避免點選過快重複請求
RxView.clicks(view).throttleFirst(1, TimeUnit.SECONDS).flatMap(new Function<Object, ObservableSource<ResultBean>>() {
@Override
public ObservableSource<ResultBean> apply(@NonNull Object o) throws Exception {
return EasyHttp.get("http://apis.juhe.cn/mobile/get")
.params("phone", "18688994275")
.params("dtype", "json")
.params("key", "5682c1f44a7f486e40f9720d6c97ffe4")
.execute(new CallClazzProxy<TestApiResult1<ResultBean>, ResultBean>(ResultBean.class) {
});
}
}).subscribe(new BaseSubscriber<ResultBean>() {
@Override
public void onError(ApiException e) {
showToast(e.getMessage());
}
@Override
public void onNext(@NonNull ResultBean resultBean) {
showToast(resultBean.toString());
}
});
複製程式碼
場景十:減少頻繁的網路請求
這裡也是主要講解RxEasyHttp如何結合rxbinding庫compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
來使用。對rxbinding庫不瞭解的,可以自己去學習一下,這裡不介紹用法。像即時搜尋功能,在輸入框中輸入內容,實時搜尋結果展示。
減少頻繁的網路請求:利用Rxjavad的debounce
操作符。
debounce:對源Observable每產生一個結果後,如果在規定的間隔時間內沒有別的結果產生,則把這個結果提交給訂閱者處理,否則忽略該結果。簡單的理解就是:當N個結點發生的時間太靠近(即發生的時間差小於設定的值T),debounce就會自動過濾掉前N-1個結點。
例如:即時搜尋,避免每輸入(刪除)一個字就做一次請求,500毫秒才讓它去請求一次網路,這樣可以避免資料混亂,也優了app效能。
Disposable mDisposable = RxTextView.textChangeEvents(mEditText)
.debounce(500, TimeUnit.MILLISECONDS).filter(new Predicate<TextViewTextChangeEvent>() {
@Override
public boolean test(@NonNull TextViewTextChangeEvent textViewTextChangeEvent) throws Exception {
// 過濾,把輸入字串長度為0時過濾掉
String key = textViewTextChangeEvent.text().toString();
//這裡可以對key進行過濾的判斷邏輯
return key.trim().length() > 0;
}
}).flatMap(new Function<TextViewTextChangeEvent, ObservableSource<Content2>>() {
@Override
public ObservableSource<Content2> apply(@NonNull TextViewTextChangeEvent textViewTextChangeEvent) throws Exception {
String key = textViewTextChangeEvent.text().toString();
Log.d("test", String.format("Searching for: %s", textViewTextChangeEvent.text().toString()));
return EasyHttp.get("/ajax.php")
.baseUrl("http://fy.iciba.com")
.params("a", "fy")
.params("f", "auto")
.params("t", "auto")
.params("w", key)
//採用代理
.execute(new CallClazzProxy<TestApiResult6<Content2>, Content2>(Content2.class) {
});
}
}).subscribeWith(new BaseSubscriber<Content2>() {
@Override
protected void onStart() {
}
@Override
public void onError(ApiException e) {
mTextView.setText(e.getMessage());
}
@Override
public void onNext(@NonNull Content2 content) {
mTextView.setText(content.toString());
}
});
//取消請求
//EasyHttp.cancelSubscription(mDisposable);
複製程式碼
場景十一:網路資料快取
網路資料快取在RxEasyHttp網路庫中已經封裝了,也就是開發者在使用網路庫過程中不必關心快取具體的實現,通過RxEasyHttp庫文件講解呼叫一些配置引數就可以實現需要的快取功能了。這裡主要講解的是不使用okhttp和Retrofit的快取,而是介紹自己如何封裝快取。RxEasyHttp網路庫除了支援無快取和預設的http快取之外,又提供了其它6種場景快取: FIRSTREMOTE:先請求網路,請求網路失敗後再載入快取 FIRSTCACHE:先載入快取,快取沒有再去請求網路 ONLYREMOTE:僅載入網路,但資料依然會被快取 ONLYCACHE:只讀取快取,快取沒有會返回null CACHEANDREMOTE:先使用快取,不管是否存在,仍然請求網路,CallBack會回撥兩次. CACHEANDREMOTEDISTINCT:先使用快取,不管是否存在,仍然請求網路,CallBack回撥不一定是兩次,如果發現請求的網路資料和快取資料是一樣的,就不會再返回網路的回撥,既回撥一次。否則不相同仍然會回撥兩次。(目的是為了防止資料沒有發生變化,也需要回撥兩次導致介面無用的重複重新整理) 如果對這部分原始碼敢興趣的請檢視RxEasyHttp原始碼,由於此部分涉及的知識點和內容比較多,篇幅問題,準備在下一篇文章中單獨介紹網路資料快取的各大場景實現,敬請期待!
結語
到這裡幾大常用的RxEasyHttp網路庫結合Rxjava2場景的例子已經介紹完了,也證明了RxEasyHttp網路庫與Rxjava2是可以完美結合的,在實際開發運用中的場景肯定有很多種,例子是怎麼也舉不完的,需要靈活運用,如何寫這一個自己的場景呢,我覺得需要如下幾點:
- 充分了解自己的需求(需要的場景),明確目的(例如:我是想做一個網路輪詢的,最終需要訂閱者給我返回什麼);
- 熟悉Rxjava操作符,看看哪個操作符是符合需求場景的,或者多個操作符串聯起來是符合需求場景,瞭解每個操作符單個用法和訂閱返回的值;
- 準備好網路請求,保證網路請求物件返回的是Observable,這樣與Rxjava結合才能成為可能;
- 將Rxjava單個操作符或者多個操作符,與網路庫的Observable進行結合,這裡面可能是需要
flatMap
,Function
等操作;
文章難免有疏漏之處,如果您有任何疑議,請反饋給我,謝謝!同時大家有與網路相關更好更常用的場景請推薦給我,我會繼續完善。喜歡請點贊,謝謝!
原始碼下載
對場景應用感興趣的小夥伴們可以將Demo下載下來進行參考。 專案地址