6章 RxJava基礎(chǔ)實戰(zhàn)

本篇文章已授權(quán)微信公眾號 YYGeeker 獨家發(fā)布轉(zhuǎn)載請標(biāo)明出處

CSDN學(xué)院課程地址

6. RxJava基礎(chǔ)實戰(zhàn)

6.1 模擬發(fā)送驗證碼

應(yīng)用場景:當(dāng)用戶點擊發(fā)送驗證碼后,在倒計時的時間內(nèi)是不可以重新點擊發(fā)送驗證碼的,倒計時結(jié)束后,發(fā)送驗證碼的按鈕重新恢復(fù)點擊,這里舉例子為3s的倒計時

public void verify(View view) {
    final long count = 3;//倒計時時間
    final Button button = (Button) view;//當(dāng)前按鈕

    Observable.interval(0, 1, TimeUnit.SECONDS)//定時器
            .take(count + 1)//取定時器前4個讨便,當(dāng)前值:0带迟,1爬立,2命锄,3
            .map(new Function<Long, Long>() {
                @Override
                public Long apply(@NonNull Long aLong) throws Exception {
                    return count - aLong;//將值轉(zhuǎn)換下堰乔,當(dāng)前值:3,2脐恩,1镐侯,0
                }
            })
            .observeOn(AndroidSchedulers.mainThread())//主線程更新UI
            .doOnSubscribe(new Consumer<Disposable>() {
                @Override
                public void accept(@NonNull Disposable disposable) throws Exception {
                    //監(jiān)聽訂閱時,將按鈕設(shè)置為不可點擊
                    button.setEnabled(false);
                    button.setTextColor(Color.BLACK);
                }
            })
            .subscribe(new Observer<Long>() {
                @Override
                public void onSubscribe(Disposable d) {}
                @Override
                public void onNext(Long aLong) {
                    //設(shè)置倒計時文本
                    button.setText("剩余" + aLong + "秒");
                }
                @Override
                public void onError(Throwable e) {}
                @Override
                public void onComplete() {
                    //事件完成后恢復(fù)點擊
                    button.setEnabled(true);
                    button.setText("發(fā)送驗證碼");
                }
            });
}

6.2 模擬用戶點擊防抖動

應(yīng)用場景:在某些應(yīng)用場景中驶冒,用戶會多次點擊同一個按鈕苟翻,導(dǎo)致有多次點擊事件的產(chǎn)生,如果點擊事件中是網(wǎng)絡(luò)請求骗污,那么就會產(chǎn)生多次網(wǎng)絡(luò)請求崇猫。正確的操作應(yīng)該是,在一定時間內(nèi)需忿,用戶頻繁點擊多次按鈕之后邓尤,只訪問一次網(wǎng)絡(luò)請求。下面針對所說的需求進行編寫

寫法一:

/**
 * 模擬用戶點擊防抖動
 */
public void query(View view) {
    RxUtils.click(view, 2)
            .subscribe(new Observer<Object>() {
                @Override
                public void onSubscribe(Disposable d) {

                }

                @Override
                public void onNext(Object o) {
                    System.out.println("onNext");
                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onComplete() {
                    System.out.println("onComplete");
                }
            });
}

//封裝工具
static class RxUtils {
    static Observable<Object> click(final View view, long seconds) {
        return new ViewClickObservable(view)
                .throttleFirst(seconds, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnDispose(new Action() {
                                 @Override
                                 public void run() throws Exception {
                                     if (view != null) {
                                         view.setOnClickListener(null);
                                     }
                                 }
                             }
                );
    }
}

//創(chuàng)建一個觀察者
static class ViewClickObservable extends Observable<Object> {

    private View view;

    public ViewClickObservable(View view) {
        this.view = view;
    }

    //當(dāng)這個觀察者被訂閱的時候贴谎,會執(zhí)行下面的回調(diào)
    @Override
    protected void subscribeActual(final Observer<? super Object> observer) {
        if (view != null) {
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    observer.onNext(v);
                }
            });
        }
    }
}

寫法二:


static class ViewClickObservableOnSubscribe implements ObservableOnSubscribe<Object> {

    private ObservableEmitter<Object> emitter;

    public ObservableEmitter<Object> getEmitter() {
        return emitter;
    }

    @Override
    public void subscribe(ObservableEmitter<Object> e) throws Exception {
        this.emitter = e;
    }
}

//封裝工具
static class RxUtils {

    static Observable<Object> clicks(final View view, long seconds) {
        final ViewClickObservableOnSubscribe viewClickObservableOnSubscribe = new ViewClickObservableOnSubscribe();

        if (view != null) {
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    ObservableEmitter<Object> emitter = viewClickObservableOnSubscribe.getEmitter();
                    if (emitter != null && !emitter.isDisposed()) {
                        emitter.onNext(1);
                    }
                }
            });
        }

        return Observable
                .create(viewClickObservableOnSubscribe)
                .throttleFirst(seconds, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnDispose(new Action() {
                                 @Override
                                 public void run() throws Exception {
                                     if (view != null) {
                                         view.setOnClickListener(null);
                                     }
                                 }
                             }
                );
    }
}

/**
 * 模擬用戶點擊防抖動
 */
public void query(View view) {
    RxUtils.clicks(view, 2)
            .subscribe(new Observer<Object>() {
                @Override
                public void onSubscribe(Disposable d) {

                }

                @Override
                public void onNext(Object o) {
                    System.out.println("onNext");
                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onComplete() {
                    System.out.println("onComplete");
                }
            });
}

6.3 模擬會員信息的合并

應(yīng)用場景:假如我們當(dāng)前在好友聊天列表界面中汞扎,客戶端需要通過好友列表的uid去查詢好友列表中會員信息,然后顯示會員圖標(biāo)等信息擅这。假如聊天列表界面中的好友數(shù)量有成千上百個澈魄,客戶端每次從后臺批量查詢用戶會員信息后,需要在本地做緩存仲翎,如果這時用戶在聊天列表中進入某個群聊界面痹扇,這個時候還是需要去獲取群聊中的所有用戶的會員信息,如果群聊界面中也包含有自己的好友溯香,那么我們就會去判斷鲫构,如果用戶的會員信息在緩存中存在,則從緩存中獲取玫坛,如果在緩存中不存在结笨,則加入到一個請求集合中,批量查詢會員信息后湿镀,合并本地緩存的會員信息和新的服務(wù)器的會員信息炕吸,將信息返回給群聊界面

1、創(chuàng)建會員實體類

private HashMap<Long, Vip> mVipCache = new HashMap<>();//作為緩存的類型

public static class Vip {
    //會員信息實體類
}

2勉痴、模擬從本地獲取數(shù)據(jù)

  1. 遍歷批量的uid參數(shù)赫模,從緩存和網(wǎng)絡(luò)中獲取會員信息的數(shù)據(jù)
  2. 如果本地數(shù)據(jù)存在,則需要將緩存的會員信息加入到vipInfo
  3. 如果本地數(shù)據(jù)不存在蒸矛,則需要將uid加入到請求列表mRequestList
  4. 最后合并本地緩存數(shù)據(jù)和網(wǎng)絡(luò)請求數(shù)據(jù)
/**
 * 從本地緩存中獲取數(shù)據(jù)
 */
public Observable<HashMap<Long, Vip>> getVipFromCache(List<Long> uids) {
    List<Long> mRequestList = new ArrayList<>();
    HashMap<Long, Vip> vipInfo = new HashMap<>();

    for (Long uid : uids) {
        if (mVipCache.containsKey(uid)) {
            Log.e("TAG", "從本地獲取數(shù)據(jù):" + uid + "用戶");
            vipInfo.put(uid, mVipCache.get(uid));//如果緩存中有數(shù)據(jù)瀑罗,則從本地中取出
        } else {
            Log.e("TAG", "從網(wǎng)絡(luò)獲取數(shù)據(jù):" + uid + "用戶");
            mRequestList.add(uid);//如果緩存中沒有數(shù)據(jù)胸嘴,則加入到網(wǎng)絡(luò)請求列表中
        }
    }

    if (mRequestList.isEmpty()) {
        //如果請求列表中為空,則直接返回緩存的數(shù)據(jù)
        return Observable.just(vipInfo);
    }

    //合并緩存的數(shù)據(jù)和網(wǎng)絡(luò)獲取的數(shù)據(jù)
    return Observable.merge(Observable.just(vipInfo), getVipFromWeb(mRequestList));
}

3斩祭、模擬從服務(wù)器獲取數(shù)據(jù)

  1. 睡眠2s鐘劣像,用于模擬網(wǎng)絡(luò)請求的耗時時間
  2. 模擬后臺返回的數(shù)據(jù),并加入到緩存列表中
  3. 返回新的事件流
/**
 * 從網(wǎng)絡(luò)上批量查詢Vip信息
 */
public Observable<HashMap<Long, Vip>> getVipFromWeb(List<Long> uids) {
    //由于這里沒有對應(yīng)的接口停忿,所以模擬請求網(wǎng)絡(luò)數(shù)據(jù)
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    //模擬返回的數(shù)據(jù)
    HashMap<Long, Vip> vip = new HashMap<>();
    for (Long uid : uids) {
        //后臺返回的數(shù)據(jù)進行賦值
        Vip vipInfo = new Vip();
        //vipInfo.xxx = WebValue;
        //vipInfo.xxx = WebValue;
        vip.put(uid, vipInfo);
    }

    //緩存到本地
    mVipCache.putAll(vip);

    return Observable.just(vip);
}

4、模擬合并本地數(shù)據(jù)和服務(wù)器數(shù)據(jù)

  1. 模擬應(yīng)用場景蚊伞,查詢當(dāng)前好友列表的會員信息
  2. 模擬應(yīng)用場景席赂,進入群聊頁面,查詢?nèi)毫牧斜淼臅T信息
  3. 模擬應(yīng)用場景时迫,定時更新會員的信息
/**
 * 模擬合并本地信息和服務(wù)器信息
 */
public void vip(View view) {
    List<Long> uids = new ArrayList<>();

    Log.e("TAG", "第一次查詢颅停,進入好友列表界面,查詢好友列表的會員信息");
    uids.add(1L);
    uids.add(2L);
    getVipFromCache(uids);
    uids.clear();

    Log.e("TAG", "第二次查詢掠拳,進入群聊界面癞揉,查詢?nèi)毫闹械臅T信息");
    uids.add(1L);
    uids.add(3L);
    uids.add(4L);
    getVipFromCache(uids);
    uids.clear();

    Log.e("TAG", "第三次查詢,定時更新最新會員信息溺欧,更新所有緩存里的數(shù)據(jù)");
    uids.add(1L);
    uids.add(2L);
    uids.add(3L);
    uids.add(4L);
    mVipCache.clear();
    getVipFromCache(uids);
}

5喊熟、輸出結(jié)果

達(dá)到我們預(yù)期的設(shè)想和最優(yōu)的解決方案

第一次查詢,進入好友列表界面姐刁,查詢好友列表的會員信息
從網(wǎng)絡(luò)獲取數(shù)據(jù):1用戶
從網(wǎng)絡(luò)獲取數(shù)據(jù):2用戶
第二次查詢芥牌,進入群聊界面,查詢?nèi)毫闹械臅T信息
從本地獲取數(shù)據(jù):1用戶
從網(wǎng)絡(luò)獲取數(shù)據(jù):3用戶
從網(wǎng)絡(luò)獲取數(shù)據(jù):4用戶
第三次查詢聂使,定時更新最新會員信息壁拉,更新所有緩存里的數(shù)據(jù)
從網(wǎng)絡(luò)獲取數(shù)據(jù):1用戶
從網(wǎng)絡(luò)獲取數(shù)據(jù):2用戶
從網(wǎng)絡(luò)獲取數(shù)據(jù):3用戶
從網(wǎng)絡(luò)獲取數(shù)據(jù):4用戶
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市柏靶,隨后出現(xiàn)的幾起案子弃理,更是在濱河造成了極大的恐慌,老刑警劉巖屎蜓,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件痘昌,死亡現(xiàn)場離奇詭異,居然都是意外死亡炬转,警方通過查閱死者的電腦和手機控汉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來返吻,“玉大人姑子,你說我怎么就攤上這事〔饨” “怎么了街佑?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵谢翎,是天一觀的道長。 經(jīng)常有香客問我沐旨,道長森逮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任磁携,我火速辦了婚禮褒侧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘谊迄。我一直安慰自己闷供,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布统诺。 她就那樣靜靜地躺著歪脏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪粮呢。 梳的紋絲不亂的頭發(fā)上婿失,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機與錄音啄寡,去河邊找鬼豪硅。 笑死,一個胖子當(dāng)著我的面吹牛挺物,可吹牛的內(nèi)容都是我干的舟误。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼姻乓,長吁一口氣:“原來是場噩夢啊……” “哼嵌溢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蹋岩,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤赖草,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后剪个,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秧骑,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年扣囊,在試婚紗的時候發(fā)現(xiàn)自己被綠了乎折。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡侵歇,死狀恐怖骂澄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情惕虑,我是刑警寧澤坟冲,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布磨镶,位于F島的核電站,受9級特大地震影響健提,放射性物質(zhì)發(fā)生泄漏琳猫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一私痹、第九天 我趴在偏房一處隱蔽的房頂上張望脐嫂。 院中可真熱鬧,春花似錦紊遵、人聲如沸账千。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蕊爵。三九已至辉哥,卻和暖如春桦山,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背醋旦。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工恒水, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人饲齐。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓钉凌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親捂人。 傳聞我的和親對象是個殘疾皇子御雕,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,101評論 1 32
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML標(biāo)準(zhǔn)滥搭。 注意:講述HT...
    kismetajun閱讀 27,486評論 1 45
  • ”最近一段時間一直在追劇酸纲,因為我特別喜歡姚晨,她演的劇很霸氣瑟匆,人物個性鮮明闽坡,真實率真不做作,對角色的把握非常到位愁溜,...
    芊淺好開心閱讀 208評論 0 5
  • 皇太極還沒來得及入主中原呢疾嗅,突然的,中風(fēng)冕象,死了代承。皇太極死的突然渐扮,還沒來得及安排接班人次泽,就撒手人寰了穿仪。結(jié)果皇太極的弟...
    梅香書宛閱讀 391評論 0 0
  • 也不知從什么時候開始,朋友圈里的結(jié)婚證書和婚紗照越來越多了意荤,曾經(jīng)一起玩的沒心沒肺的小伙伴們啊片,穿上西裝革履或者一席白...
    錫平君閱讀 409評論 0 5