前言
繼續(xù)上篇的Rxjava2的入門實例,把剩下的運用Rxjava的實例講下,首先要說名下本文會用到Rxbinding的知識,他相當于Rxjava的輔助工具,在引入他的時候會自動幫我們引入Rxjava,在本文中我就不具體講解了,用法比較簡單,沒解除的同學找些相關的文章,相信很快就能上手的,。在這里我把依賴寫下
compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
這個版本默認引入的是Rxjava2.0.2的版本
Rxjava2的操作符
- create
- just
- fromArray
- map
- flatMap
- zip
- filter
- time
- merge
- retry
- retryWhen
- range
- Interval
- ...
Rxjava2的使用場景
- 登陸后獲取用戶信息
- 關鍵詞搜索
- 防止按鈕重復點擊
- 購物車合并本地和網絡數(shù)據(jù)
- 發(fā)送驗證碼倒計時
關鍵詞搜索
一般情況我們監(jiān)聽EditText控件,當值發(fā)生改變去請求搜索接口,如下:
a: 可能導致很多沒有意義的請求,耗費用戶流量(因為控件的值每更改一次立即就會去請求網絡,而且只是最后輸入的關鍵字是有用的)
b:可能導致最終搜索的結果不是用戶想要的.
例如,用戶一開始輸入關鍵字’AB’ 這個時候出現(xiàn)兩個請求, 一個請求是A關鍵字, 一個請求是AB關鍵字. 表面上是’A’請求先發(fā)出去, ‘AB’請求后發(fā)出去. 如果后發(fā)出去的’AB’請求先返回, ‘A’請求后返回,那么’A’請求后的結果將會覆蓋’AB’請求的結果. 從而導致搜索結果不正確.
在寫代碼之前我們先介紹下我們要用到的操作符debounce它屬于過濾操作符
這是官方文檔給出的解釋,從解釋中我們也不難看出他的用法。那么下面我在實例中去使用吧!
RxTextView.textChanges(mView)//通過Rxbinding的textChanges()監(jiān)聽AutoCompleteTextView文字的變化,他是一個Obervable對象
.debounce(200, TimeUnit.MILLISECONDS)//利用debounce操作符延遲發(fā)送 TimeUnit.MILLISECONDS(毫秒)指定一個參數(shù)的單位
.subscribeOn(AndroidSchedulers.mainThread())//通過Rxbinding監(jiān)聽控件必須在主線程
.filter(new Predicate<CharSequence>() {
@Override
public boolean test(CharSequence charSequence) throws Exception {
//過濾為空的數(shù)據(jù) 避免多余請求
return charSequence.toString().trim().length() > 0;
}
})
.flatMap(new Function<CharSequence, ObservableSource<List<String>>>() {
@Override
public ObservableSource<List<String>> apply(CharSequence charSequence) throws Exception {
Log.d(TAG, "apply: " + charSequence.toString());
String request = charSequence.toString().trim();//輸入的內容
/**
* 通過輸入的內容request發(fā)起網絡請求
* 返回一個模糊匹配的字符串集合用于顯示
* 這里我們構建一個假的數(shù)據(jù)
*/
List<String> mList = new ArrayList<String>();
mList.add("abc");
mList.add("abd");
mList.add("abop");
mList.add("ac");
return Observable.just(mList);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<String>>() {
@Override
public void accept(List<String> strings) throws Exception {
Log.d(TAG, "accept: " + strings.toString());
ArrayAdapter<String> adapter = new ArrayAdapter<String>
(getApplicationContext(), android.R.layout.simple_list_item_1, android.R.id.text1, strings);
mView.setAdapter(adapter);
}
});
}
這就是一個簡單模擬關鍵詞搜索的實例,但是雖然我們滿足了上面提到的要求a,但是要求b也就是可能返回的數(shù)據(jù)先后不同可能會導致結果不是們想要的,那么該怎么處理呢?通過文檔我們找到了這樣一個操作符switchMap,讓我們來看看他的使用
這個操作符正好符合我們的業(yè)務要求,同時他也屬于變換操作符,所以我們自需要把flatmap改成switchMap就可以了。這樣我們2者的區(qū)別和debounce的用法結合實例是不是更加深刻呢?
防止按鈕重復(連續(xù))點擊
在實際應用中可能在提交信息,登錄的時候每次點擊按鈕就會發(fā)送網絡請求,當網絡比較慢的時候或是其他原因已經請求網路只是返回的數(shù)據(jù)比較慢,當我們連續(xù)點擊就會連續(xù)的發(fā)送請求,這樣的結果必然不是我們想要的。
ThrottleFirst:
允許設置一個時間長度,之后它會發(fā)送固定時間長度內的第一個事件,而屏蔽其它事件,在間隔達到設置的時間后,可以再發(fā)送下一個事件
這個操作符就很好的解決了這個問題
RxView.clicks(mButton).throttleFirst(2, TimeUnit.SECONDS).subscribe(new Consumer<Object>() {
@Override
public void accept(Object o) throws Exception {
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = dateformat.format(System.currentTimeMillis());
Log.d(TAG, "accept: "+dateStr);
}
});
我在不斷點擊的情況下,輸出結果:
10-08 21:51:07.008 3950-3950/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 2017-10-08 21:51:07
10-08 21:51:09.168 3950-3950/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 2017-10-08 21:51:09
10-08 21:51:11.308 3950-3950/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 2017-10-08 21:51:11
10-08 21:51:13.398 3950-3950/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 2017-10-08 21:51:13
可以看到2秒內自能點擊一次。
注意:此時可以用ThrottleFirst也可以用debounce 效果是一樣的 但是 ThrottleFirst發(fā)出的是第一個 debounce 發(fā)出的是最后一個 都是保證單位時間內只能發(fā)送一次 但是原理還是有些不同的,過會2個例子也不難比較區(qū)別
購物車合并本地和網絡數(shù)據(jù)
現(xiàn)在有這么一種情況,你在上班的時候偷偷用電腦上淘寶準備買衣服看重了一雙鞋子和衣服加入購物車。在回家的路上用手機又加入購物車褲子和襯衫。等你回家的時候準備用手機購買,購物車里應該是所有的商品都在的,那么我們就需要把手機的和web端合并在一起并展示。這時我們就可以用到merge操作符。
在使用前我們先了解下merge:
關于merge的官方文檔和圖片分析還是比較簡單的。不理解的話等我們講完實例后回頭在來看看。下面是具體代碼:
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
/*兩者合并*/
Observable.merge(getObervableLocal(), getObervableWeb()).subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe(new Consumer<List<User>>() {
@Override
public void accept(List<User> users) throws Exception {
for (int i = 0; i <users.size() ; i++) {
Log.d(TAG, "accept: "+users.get(i).getName());
}
}
});
}
});
}
/**
* 本地數(shù)據(jù)(從數(shù)據(jù)庫中取)
*
* @return 返回本地數(shù)據(jù)(手機端)的購物車信息
*/
public Observable<List<User>> getObervableLocal() {
//用User對象代表商品實例
//我們用手機購買一般數(shù)據(jù)會緩存到手機的數(shù)據(jù)庫當中
User user = new User("褲子", "16元");
User user1 = new User("襯衫", "18元");
List<User> mList = new ArrayList<>();
mList.add(user);
mList.add(user1);
return Observable.just(mList);
}
/**
* web數(shù)據(jù)(從網絡中請求)
*
* @return 返回網絡數(shù)據(jù)
*/
public Observable<List<User>> getObervableWeb() {
//網絡請求 查看服務器購物車是否有數(shù)據(jù)
User user = new User("衣服", "20元");
User user1 = new User("褲子", "22元");
List<User> mList = new ArrayList<>();//模擬請求返回的數(shù)據(jù)
mList.add(user);
mList.add(user1);
return Observable.fromArray(mList).subscribeOn(Schedulers.io());//網絡請求在子線程
}
運行結果:
10-09 12:39:08.678 11602-11602/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 褲子
10-09 12:39:08.678 11602-11602/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 襯衫
10-09 12:39:08.678 11602-11602/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 衣服
10-09 12:39:08.678 11602-11602/com.example.ggxiaozhi.rxjava D/Main3Activity: accept: 褲子
注意其實合并的操作符還有zip和zipWith,其實2者差不多只是參數(shù)不一樣。用法也是比較簡單zip操作符也可以看看這篇文章。實際操作下會更加深印象。這里我就不咱代碼了。
發(fā)送驗證碼倒計時
這個實例我們用到Interval操作符:
具體代碼操作:
所有的實例都講完了我們在看下retryWhen和retry,range操作符。
retryWhen和retry的主要區(qū)別概括來說就是retryWhen將錯誤的信息發(fā)送下去(出錯了就發(fā)送錯誤信息),retry是出錯了會先嘗試重新訂閱再發(fā)送一變,當達到設置的重試次數(shù)時還沒有成功才會發(fā)出錯誤的信息
總結:感覺文章寫的好亂,主要的原因是因為本身也在學習中很多東西總結的不夠透徹,雖然看了很多文章但是自己寫起來還是會亂亂的,以后會努力希望一次比一次好,作為小白,這是我自身的學習筆記。如果有錯誤希望大家指出,我將不勝感激。
推薦文章:
Rxjava2
RxJava2操作符
RxJava/RxAndroid 使用實例實踐
Rxjava2我覺得關于rxjava2這個系列真的非常好很值得學習