Rxjava2-小白入門(三)

前言

繼續上篇的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的使用場景

  • 登陸後獲取用戶信息
  • 關鍵詞搜索
  • 防止按鈕重複點擊
  • 購物車合併本地和網絡數據
  • 發送驗證碼倒計時

關鍵詞搜索

一般情況我們監聽EditText控件,當值發生改變去請求搜索接口,如下:

a: 可能導致很多沒有意義的請求,耗費用戶流量(因爲控件的值每更改一次立即就會去請求網絡,而且只是最後輸入的關鍵字是有用的)

b:可能導致最終搜索的結果不是用戶想要的.
例如,用戶一開始輸入關鍵字’AB’ 這個時候出現兩個請求, 一個請求是A關鍵字, 一個請求是AB關鍵字. 表面上是’A’請求先發出去, ‘AB’請求後發出去. 如果後發出去的’AB’請求先返回, ‘A’請求後返回,那麼’A’請求後的結果將會覆蓋’AB’請求的結果. 從而導致搜索結果不正確.

在寫代碼之前我們先介紹下我們要用到的操作符debounce它屬於過濾操作符

這是官方文檔給出的解釋,從解釋中我們也不難看出他的用法。那麼下面我在實例中去使用吧!

 RxTextView.textChanges(mView)//通過Rxbinding的textChanges()監聽AutoCompleteTextView文字的變化,他是一個Obervable對象
                .debounce(200, TimeUnit.MILLISECONDS)//利用debounce操作符延遲發送 TimeUnit.MILLISECONDS(毫秒)指定一個參數的單位
                .subscribeOn(AndroidSchedulers.mainThread())//通過Rxbinding監聽控件必須在主線程
                .filter(new Predicate<CharSequence>() {
                    @Override
                    public boolean test(CharSequence charSequence) throws Exception {
                        //過濾爲空的數據 避免多餘請求
                        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發起網絡請求
                         * 返回一個模糊匹配的字符串集合用於顯示
                         * 這裏我們構建一個假的數據
                         */
                        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也就是可能返回的數據先後不同可能會導致結果不是們想要的,那麼該怎麼處理呢?通過文檔我們找到了這樣一個操作符switchMap,讓我們來看看他的使用

這個操作符正好符合我們的業務要求,同時他也屬於變換操作符,所以我們自需要把flatmap改成switchMap就可以了。這樣我們2者的區別和debounce的用法結合實例是不是更加深刻呢?


防止按鈕重複(連續)點擊

在實際應用中可能在提交信息,登錄的時候每次點擊按鈕就會發送網絡請求,當網絡比較慢的時候或是其他原因已經請求網路只是返回的數據比較慢,當我們連續點擊就會連續的發送請求,這樣的結果必然不是我們想要的。

ThrottleFirst:
允許設置一個時間長度,之後它會發送固定時間長度內的第一個事件,而屏蔽其它事件,在間隔達到設置的時間後,可以再發送下一個事件

這個操作符就很好的解決了這個問題

 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發出的是第一個 debounce 發出的是最後一個 都是保證單位時間內只能發送一次 但是原理還是有些不同的,過會2個例子也不難比較區別


購物車合併本地和網絡數據

現在有這麼一種情況,你在上班的時候偷偷用電腦上淘寶準備買衣服看重了一雙鞋子和衣服加入購物車。在回家的路上用手機又加入購物車褲子和襯衫。等你回家的時候準備用手機購買,購物車裏應該是所有的商品都在的,那麼我們就需要把手機的和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());
                                }
                            }
                        });
            }
        });
    }
    /**
     * 本地數據(從數據庫中取)
     *
     * @return 返回本地數據(手機端)的購物車信息
     */
    public Observable<List<User>> getObervableLocal() {
        //用User對象代表商品實例
        //我們用手機購買一般數據會緩存到手機的數據庫當中
        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數據(從網絡中請求)
     *
     * @return 返回網絡數據
     */
    public Observable<List<User>> getObervableWeb() {
        //網絡請求 查看服務器購物車是否有數據
        User user = new User("衣服", "20元");
        User user1 = new User("褲子", "22元");

        List<User> mList = new ArrayList<>();//模擬請求返回的數據
        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者差不多隻是參數不一樣。用法也是比較簡單zip操作符也可以看看這篇文章。實際操作下會更加深印象。這裏我就不咱代碼了。


發送驗證碼倒計時

這個實例我們用到Interval操作符:


具體代碼操作:



所有的實例都講完了我們在看下retryWhen和retry,range操作符。

retry操作符

retryWhen和retry的主要區別概括來說就是retryWhen將錯誤的信息發送下去(出錯了就發送錯誤信息),retry是出錯了會先嚐試重新訂閱再發送一變,當達到設置的重試次數時還沒有成功纔會發出錯誤的信息


總結:感覺文章寫的好亂,主要的原因是因爲本身也在學習中很多東西總結的不夠透徹,雖然看了很多文章但是自己寫起來還是會亂亂的,以後會努力希望一次比一次好,作爲小白,這是我自身的學習筆記。如果有錯誤希望大家指出,我將不勝感激。

推薦文章:
Rxjava2
RxJava2操作符
RxJava/RxAndroid 使用實例實踐
Rxjava2我覺得關於rxjava2這個系列真的非常好很值得學習

代碼地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章