前言
繼續(xù)上篇的Rxjava2的入門實(shí)例缝呕,把剩下的運(yùn)用Rxjava的實(shí)例講下枫夺,首先要說名下本文會(huì)用到Rxbinding的知識(shí)昭殉,他相當(dāng)于Rxjava的輔助工具忙干,在引入他的時(shí)候會(huì)自動(dòng)幫我們引入Rxjava上祈,在本文中我就不具體講解了培遵,用法比較簡單,沒解除的同學(xué)找些相關(guān)的文章登刺,相信很快就能上手的荤懂,。在這里我把依賴寫下
compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
這個(gè)版本默認(rèn)引入的是Rxjava2.0.2的版本
Rxjava2的操作符
- create
- just
- fromArray
- map
- flatMap
- zip
- filter
- time
- merge
- retry
- retryWhen
- range
- Interval
- ...
Rxjava2的使用場(chǎng)景
- 登陸后獲取用戶信息
- 關(guān)鍵詞搜索
- 防止按鈕重復(fù)點(diǎn)擊
- 購物車合并本地和網(wǎng)絡(luò)數(shù)據(jù)
- 發(fā)送驗(yàn)證碼倒計(jì)時(shí)
關(guān)鍵詞搜索
一般情況我們監(jiān)聽EditText控件,當(dāng)值發(fā)生改變?nèi)フ?qǐng)求搜索接口塘砸,如下:
a: 可能導(dǎo)致很多沒有意義的請(qǐng)求,耗費(fèi)用戶流量(因?yàn)榭丶闹得扛囊淮瘟⒓淳蜁?huì)去請(qǐng)求網(wǎng)絡(luò)节仿,而且只是最后輸入的關(guān)鍵字是有用的)
b:可能導(dǎo)致最終搜索的結(jié)果不是用戶想要的.
例如,用戶一開始輸入關(guān)鍵字’AB’ 這個(gè)時(shí)候出現(xiàn)兩個(gè)請(qǐng)求, 一個(gè)請(qǐng)求是A關(guān)鍵字, 一個(gè)請(qǐng)求是AB關(guān)鍵字. 表面上是’A’請(qǐng)求先發(fā)出去, ‘AB’請(qǐng)求后發(fā)出去. 如果后發(fā)出去的’AB’請(qǐng)求先返回, ‘A’請(qǐng)求后返回,那么’A’請(qǐng)求后的結(jié)果將會(huì)覆蓋’AB’請(qǐng)求的結(jié)果. 從而導(dǎo)致搜索結(jié)果不正確.
在寫代碼之前我們先介紹下我們要用到的操作符debounce它屬于過濾操作符
這是官方文檔給出的解釋,從解釋中我們也不難看出他的用法掉蔬。那么下面我在實(shí)例中去使用吧廊宪!
RxTextView.textChanges(mView)//通過Rxbinding的textChanges()監(jiān)聽AutoCompleteTextView文字的變化,他是一個(gè)Obervable對(duì)象
.debounce(200, TimeUnit.MILLISECONDS)//利用debounce操作符延遲發(fā)送 TimeUnit.MILLISECONDS(毫秒)指定一個(gè)參數(shù)的單位
.subscribeOn(AndroidSchedulers.mainThread())//通過Rxbinding監(jiān)聽控件必須在主線程
.filter(new Predicate<CharSequence>() {
@Override
public boolean test(CharSequence charSequence) throws Exception {
//過濾為空的數(shù)據(jù) 避免多余請(qǐng)求
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();//輸入的內(nèi)容
/**
* 通過輸入的內(nèi)容request發(fā)起網(wǎng)絡(luò)請(qǐng)求
* 返回一個(gè)模糊匹配的字符串集合用于顯示
* 這里我們構(gòu)建一個(gè)假的數(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);
}
});
}
這就是一個(gè)簡單模擬關(guān)鍵詞搜索的實(shí)例,但是雖然我們滿足了上面提到的要求a女轿,但是要求b也就是可能返回的數(shù)據(jù)先后不同可能會(huì)導(dǎo)致結(jié)果不是們想要的箭启,那么該怎么處理呢?通過文檔我們找到了這樣一個(gè)操作符switchMap蛉迹,讓我們來看看他的使用
這個(gè)操作符正好符合我們的業(yè)務(wù)要求傅寡,同時(shí)他也屬于變換操作符,所以我們自需要把flatmap改成switchMap就可以了北救。這樣我們2者的區(qū)別和debounce的用法結(jié)合實(shí)例是不是更加深刻呢荐操?
防止按鈕重復(fù)(連續(xù))點(diǎn)擊
在實(shí)際應(yīng)用中可能在提交信息,登錄的時(shí)候每次點(diǎn)擊按鈕就會(huì)發(fā)送網(wǎng)絡(luò)請(qǐng)求珍策,當(dāng)網(wǎng)絡(luò)比較慢的時(shí)候或是其他原因已經(jīng)請(qǐng)求網(wǎng)路只是返回的數(shù)據(jù)比較慢托启,當(dāng)我們連續(xù)點(diǎn)擊就會(huì)連續(xù)的發(fā)送請(qǐng)求,這樣的結(jié)果必然不是我們想要的攘宙。
ThrottleFirst:
允許設(shè)置一個(gè)時(shí)間長度屯耸,之后它會(huì)發(fā)送固定時(shí)間長度內(nèi)的第一個(gè)事件拐迁,而屏蔽其它事件,在間隔達(dá)到設(shè)置的時(shí)間后疗绣,可以再發(fā)送下一個(gè)事件
這個(gè)操作符就很好的解決了這個(gè)問題
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);
}
});
我在不斷點(diǎn)擊的情況下线召,輸出結(jié)果:
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秒內(nèi)自能點(diǎn)擊一次。
注意:此時(shí)可以用ThrottleFirst也可以用debounce 效果是一樣的 但是 ThrottleFirst發(fā)出的是第一個(gè) debounce 發(fā)出的是最后一個(gè) 都是保證單位時(shí)間內(nèi)只能發(fā)送一次 但是原理還是有些不同的多矮,過會(huì)2個(gè)例子也不難比較區(qū)別
購物車合并本地和網(wǎng)絡(luò)數(shù)據(jù)
現(xiàn)在有這么一種情況缓淹,你在上班的時(shí)候偷偷用電腦上淘寶準(zhǔn)備買衣服看重了一雙鞋子和衣服加入購物車。在回家的路上用手機(jī)又加入購物車褲子和襯衫工窍。等你回家的時(shí)候準(zhǔn)備用手機(jī)購買割卖,購物車?yán)飸?yīng)該是所有的商品都在的,那么我們就需要把手機(jī)的和web端合并在一起并展示患雏。這時(shí)我們就可以用到merge操作符鹏溯。
在使用前我們先了解下merge:
關(guān)于merge的官方文檔和圖片分析還是比較簡單的。不理解的話等我們講完實(shí)例后回頭在來看看淹仑。下面是具體代碼:
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());
}
}
});
}
});
}
/**
* 本地?cái)?shù)據(jù)(從數(shù)據(jù)庫中取)
*
* @return 返回本地?cái)?shù)據(jù)(手機(jī)端)的購物車信息
*/
public Observable<List<User>> getObervableLocal() {
//用User對(duì)象代表商品實(shí)例
//我們用手機(jī)購買一般數(shù)據(jù)會(huì)緩存到手機(jī)的數(shù)據(jù)庫當(dāng)中
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ù)(從網(wǎng)絡(luò)中請(qǐng)求)
*
* @return 返回網(wǎng)絡(luò)數(shù)據(jù)
*/
public Observable<List<User>> getObervableWeb() {
//網(wǎng)絡(luò)請(qǐng)求 查看服務(wù)器購物車是否有數(shù)據(jù)
User user = new User("衣服", "20元");
User user1 = new User("褲子", "22元");
List<User> mList = new ArrayList<>();//模擬請(qǐng)求返回的數(shù)據(jù)
mList.add(user);
mList.add(user1);
return Observable.fromArray(mList).subscribeOn(Schedulers.io());//網(wǎng)絡(luò)請(qǐng)求在子線程
}
運(yùn)行結(jié)果:
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: 褲子
注意其實(shí)合并的操作符還有zip和zipWith丙挽,其實(shí)2者差不多只是參數(shù)不一樣。用法也是比較簡單zip操作符也可以看看這篇文章匀借。實(shí)際操作下會(huì)更加深印象颜阐。這里我就不咱代碼了。
發(fā)送驗(yàn)證碼倒計(jì)時(shí)
這個(gè)實(shí)例我們用到Interval操作符:
具體代碼操作:
所有的實(shí)例都講完了我們?cè)诳聪聄etryWhen和retry吓肋,range操作符凳怨。
retryWhen和retry的主要區(qū)別概括來說就是retryWhen將錯(cuò)誤的信息發(fā)送下去(出錯(cuò)了就發(fā)送錯(cuò)誤信息),retry是出錯(cuò)了會(huì)先嘗試重新訂閱再發(fā)送一變是鬼,當(dāng)達(dá)到設(shè)置的重試次數(shù)時(shí)還沒有成功才會(huì)發(fā)出錯(cuò)誤的信息
總結(jié):感覺文章寫的好亂肤舞,主要的原因是因?yàn)楸旧硪苍趯W(xué)習(xí)中很多東西總結(jié)的不夠透徹,雖然看了很多文章但是自己寫起來還是會(huì)亂亂的均蜜,以后會(huì)努力希望一次比一次好李剖,作為小白,這是我自身的學(xué)習(xí)筆記囤耳。如果有錯(cuò)誤希望大家指出篙顺,我將不勝感激。
推薦文章:
Rxjava2
RxJava2操作符
RxJava/RxAndroid 使用實(shí)例實(shí)踐
Rxjava2我覺得關(guān)于rxjava2這個(gè)系列真的非常好很值得學(xué)習(xí)