RxJava2 實戰知識梳理(2) 計算一段時間內資料的平均值

澤毛發表於2017-12-21

一、前言

今天,我們繼續跟著 RxJava-Android-Samples 的腳步,一起看一下RxJava2在實戰當中的應用,在這個專案中,第二個的例子的描述如下:

RxJava2 實戰知識梳理(2)   計算一段時間內資料的平均值
簡單地翻譯過來:如果在2s內連續點選了一個按鈕五次,那麼我們只會收到一個“你點選了該按鈕五次”的時間,而不是五個"你點選了該按鈕"的事件。這個示例的目的是讓我們學會如何應用buffer操作符。

二、示例

2.1 應用場景

仔細思考了一下,在平時的專案中,我們似乎不會遇到需要統計一段時間內使用者點選了多少次按鈕這種需求。

但是,我們有時候會需要計算一段時間內的平均資料,例如統計一段時間內的平均溫度,或者統計一段時間內的平均位置。在接觸RxJava之前,我們一般會將這段時間內統計到的資料都暫時存起來,等到需要更新的時間點到了之後,再把這些資料結合起來,計算這些資料的平均值。

現在,我們就來看一下,用RxJava2如何去實現這個需求。

2.2 示例程式碼

這裡,我們通過一個Handler迴圈地傳送訊息,實現間隔一定時間進行溫度的測量,但是在測量之後,我們並不實時地更新介面的溫度顯示,而是每隔3s統計一次過去這段時間內的平均溫度。

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() + "個資料, 平均溫度為:" + 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", "溫度測量結果:" + 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);
            //迴圈地傳送。
            sendEmptyMessageDelayed(0, 250 + (long) (250 * Math.random()));
        }
    }

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

    }
}
複製程式碼

實際的執行結果為:

RxJava2 實戰知識梳理(2)   計算一段時間內資料的平均值
控制檯輸出的資訊為:
RxJava2 實戰知識梳理(2)   計算一段時間內資料的平均值

三、示例解析

3.1 原理

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

RxJava2 實戰知識梳理(2)   計算一段時間內資料的平均值
函式中的兩個形參分別對應是時間的值和單位,這樣,當我們通過下面這句傳送事件:

mPublishSubject.onNext(temperature);
複製程式碼

事件並不會直接傳遞到ObserveronNext方法中,而是放在緩衝區中,直到事件到之後,再將所有在這段緩衝事件內放入緩衝區中的值,放在一個List中一起傳送到下游。

3.2 Buffer 的其它用法

關於Buffer的其它用法,這篇文章寫得很全,我這裡就不詳細贅述了,大家可以參考:RxJava 的學習之變換操作符 - Buffer

四、參考文獻

RxJava 的學習之變換操作符 - Buffer


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

相關文章