RxJava2 實(shí)戰(zhàn)知識(shí)梳理(2) - 計(jì)算一段時(shí)間內(nèi)數(shù)據(jù)的平均值

RxJava2 實(shí)戰(zhàn)系列文章

RxJava2 實(shí)戰(zhàn)知識(shí)梳理(1) - 后臺(tái)執(zhí)行耗時(shí)操作,實(shí)時(shí)通知 UI 更新
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(2) - 計(jì)算一段時(shí)間內(nèi)數(shù)據(jù)的平均值
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(3) - 優(yōu)化搜索聯(lián)想功能
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(4) - 結(jié)合 Retrofit 請(qǐng)求新聞資訊
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(5) - 簡單及進(jìn)階的輪詢操作
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(6) - 基于錯(cuò)誤類型的重試請(qǐng)求
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(7) - 基于 combineLatest 實(shí)現(xiàn)的輸入表單驗(yàn)證
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(8) - 使用 publish + merge 優(yōu)化先加載緩存,再讀取網(wǎng)絡(luò)數(shù)據(jù)的請(qǐng)求過程
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(9) - 使用 timer/interval/delay 實(shí)現(xiàn)任務(wù)調(diào)度
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(10) - 屏幕旋轉(zhuǎn)導(dǎo)致 Activity 重建時(shí)恢復(fù)任務(wù)
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(11) - 檢測網(wǎng)絡(luò)狀態(tài)并自動(dòng)重試請(qǐng)求
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(12) - 實(shí)戰(zhàn)講解 publish & replay & share & refCount & autoConnect
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(13) - 如何使得錯(cuò)誤發(fā)生時(shí)不自動(dòng)停止訂閱關(guān)系
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(14) - 在 token 過期時(shí),刷新過期 token 并重新發(fā)起請(qǐng)求
RxJava2 實(shí)戰(zhàn)知識(shí)梳理(15) - 實(shí)現(xiàn)一個(gè)簡單的 MVP + RxJava + Retrofit 應(yīng)用


一、前言

今天,我們繼續(xù)跟著 RxJava-Android-Samples 的腳步,一起看一下RxJava2在實(shí)戰(zhàn)當(dāng)中的應(yīng)用,在這個(gè)項(xiàng)目中,第二個(gè)的例子的描述如下:


簡單地翻譯過來:如果在2s內(nèi)連續(xù)點(diǎn)擊了一個(gè)按鈕五次,那么我們只會(huì)收到一個(gè)“你點(diǎn)擊了該按鈕五次”的時(shí)間,而不是五個(gè)"你點(diǎn)擊了該按鈕"的事件。這個(gè)示例的目的是讓我們學(xué)會(huì)如何應(yīng)用buffer操作符。

二、示例

2.1 應(yīng)用場景

仔細(xì)思考了一下,在平時(shí)的項(xiàng)目中,我們似乎不會(huì)遇到需要統(tǒng)計(jì)一段時(shí)間內(nèi)用戶點(diǎn)擊了多少次按鈕這種需求。

但是,我們有時(shí)候會(huì)需要計(jì)算一段時(shí)間內(nèi)的平均數(shù)據(jù),例如統(tǒng)計(jì)一段時(shí)間內(nèi)的平均溫度,或者統(tǒng)計(jì)一段時(shí)間內(nèi)的平均位置。在接觸RxJava之前,我們一般會(huì)將這段時(shí)間內(nèi)統(tǒng)計(jì)到的數(shù)據(jù)都暫時(shí)存起來,等到需要更新的時(shí)間點(diǎn)到了之后,再把這些數(shù)據(jù)結(jié)合起來,計(jì)算這些數(shù)據(jù)的平均值。

現(xiàn)在,我們就來看一下,用RxJava2如何去實(shí)現(xiàn)這個(gè)需求。

2.2 示例代碼

這里,我們通過一個(gè)Handler循環(huán)地發(fā)送消息,實(shí)現(xiàn)間隔一定時(shí)間進(jìn)行溫度的測量,但是在測量之后,我們并不實(shí)時(shí)地更新界面的溫度顯示,而是每隔3s統(tǒng)計(jì)一次過去這段時(shí)間內(nèi)的平均溫度。

public class BufferActivity extends AppCompatActivity {

    private PublishSubject<Double> mPublishSubject;
    private CompositeDisposable mCompositeDisposable;
    private TextView mTv;
    private SourceHandler mSourceHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_buffer);
        mTv = (TextView) findViewById(R.id.tv_buffer);
        mPublishSubject = PublishSubject.create();
        DisposableObserver<List<Double>> disposableObserver = new DisposableObserver<List<Double>>() {
            @Override
            public void onNext(List<Double> o) {
                double result = 0;
                if (o.size() > 0) {
                    for (Double d : o) {
                        result += d;
                    }
                    result = result / o.size();
                }
                Log.d("BufferActivity", "更新平均溫度:" + result);
                mTv.setText("過去3秒收到了" + o.size() + "個(gè)數(shù)據(jù), 平均溫度為:" + result);
            }

            @Override
            public void onError(Throwable throwable) {

            }

            @Override
            public void onComplete() {

            }
        };
        mPublishSubject.buffer(3000, TimeUnit.MILLISECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(disposableObserver);
        mCompositeDisposable = new CompositeDisposable();
        mCompositeDisposable.add(disposableObserver);
        //開始測量溫度。
        mSourceHandler = new SourceHandler();
        mSourceHandler.sendEmptyMessage(0);
    }

    public void updateTemperature(double temperature) {
        Log.d("BufferActivity", "溫度測量結(jié)果:" + temperature);
        mPublishSubject.onNext(temperature);
    }

    private class SourceHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            double temperature = Math.random() * 25 + 5;
            updateTemperature(temperature);
            //循環(huán)地發(fā)送。
            sendEmptyMessageDelayed(0, 250 + (long) (250 * Math.random()));
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mSourceHandler.removeCallbacksAndMessages(null);
        mCompositeDisposable.clear();

    }
}

實(shí)際的運(yùn)行結(jié)果為:



控制臺(tái)輸出的信息為:


三、示例解析

3.1 原理

在上面的例子中,我們使用了buffer(int time, Unit timeUnit),其原理圖如下所示:


函數(shù)中的兩個(gè)形參分別對(duì)應(yīng)是時(shí)間的值和單位,這樣,當(dāng)我們通過下面這句發(fā)送事件:

mPublishSubject.onNext(temperature);

事件并不會(huì)直接傳遞到ObserveronNext方法中,而是放在緩沖區(qū)中,直到事件到之后,再將所有在這段緩沖事件內(nèi)放入緩沖區(qū)中的值,放在一個(gè)List中一起發(fā)送到下游。

3.2 Buffer 的其它用法

關(guān)于Buffer的其它用法,這篇文章寫得很全,我這里就不詳細(xì)贅述了,大家可以參考:RxJava 的學(xué)習(xí)之變換操作符 - Buffer

四、參考文獻(xiàn)

RxJava 的學(xué)習(xí)之變換操作符 - Buffer


更多文章,歡迎訪問我的 Android 知識(shí)梳理系列:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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