4

RxJava に慣れようとしています。私が達成しようとしているユースケースは次のとおりです。

画面にボタンがあり、タップ数を収集しようとしています。そのため、ユーザーがボタンをタップすると、クリックが登録され、ログが生成されます。ユーザーがボタンを 2 回クリックすると、両方のクリックが登録されて収集され、1 ではなく 2 が出力されます。

基本的に、一定期間にわたってクリック数を蓄積し、最終結果を吐き出そうとしています。「buffer」は、使用する必要がある方法だと思います。Android で簡単な例を作成しました (コードは次のとおりです) が、バッファ メソッドは、すべてのイベント入力を収集してコレクションを吐き出すほど単純ではないようです。

public class DemoFragment
    extends Fragment {

    private int _tapCount = 0;
    private Observable<List<Integer>> _bufferedObservable;
    private Observer<List<Integer>> _observer;

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        _setupLogger();

        _bufferedObservable = _getBufferedObservable();
        _observer = _getObserver();
    }


    // the library butterknife allows this
    @OnClick(R.id.btn_start_operation)
    public void onButtonTapped() {
        _log("GOT A TAP");
        _bufferedObservable.subscribeOn(Schedulers.io())
                         .observeOn(AndroidSchedulers.mainThread())
                         .subscribe(_observer);
    }

    private Observable<List<Integer>> _getBufferedObservable() {
        return Observable.create(new Observable.OnSubscribe<Integer>() {


            @Override
            public void call(Subscriber<? super Integer> subscriber) {
                subscriber.onNext(1);   // send one tap here
            }

        }).buffer(2, TimeUnit.SECONDS); // collect all taps in the last 2s
    }

    private Observer<List<Integer>> _getObserver() {
        return new Observer<List<Integer>>() {


            @Override
            public void onCompleted() {
                _log(String.format("%d taps", _tapCount));
                _tapCount = 0; // reset tap count
            }

            @Override
            public void onError(Throwable e) {}

            @Override
            public void onNext(List<Integer> integers) {
                if (integers.size() > 0) {
                    for (int i : integers) {
                        _tapCount += i;
                    }
                    onCompleted();
                } else {
                    _log("No taps received");
                }
            }
        };
    }

    // ... other method that help wiring up the example (irrelevant to RxJava)
}

ここで私の理解における誤解を理解するのを手伝ってくれる人はいますか?

問題 1_getObserver() :さんonNextから累積タップ数のリストが送られてくることを期待しています。したがって、ボタンが 5 回押された場合、それぞれの値が「1」である 5 つの項目を含むリストが期待されます。既存のコードでは、常に空のリストを取得しています。

問題 2List<Integer> integers :サイズを確認してイベントが受信されない場合は、基本的にコンソール ログを実行します。リストが空でない場合は、「タップを受信して​​いません」というコンソール ログをスローします。Observable は決して停止しないようです。ボタンタップが登録されていない場合でも、タイマーのように常に動き続けます。過去10秒間にイベントが登録されていない場合、Observableを停止する方法はありますか?

問題 3 : エミットの数がほぼ指数関数的に増加しているように見えます。それは、以前のすべてのボタンの空のタップを集めているようなものです。

4

3 に答える 3

8

これが私がそれを行う方法を示すコードです(ボタンのIDが であると仮定しますR.id.rx_button):

private Subscription mSubscription;

@Override
protected void onResume() {
    super.onResume();
    mSubscription = Observable.create(new OnSubscribe<Integer>() {
        @Override
        public void call(Subscriber<? super Integer> subscriber) {
            findViewById(R.id.rx_button).setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    subscriber.onNext(1);
                }
            });
        }
    }).buffer(2, TimeUnit.SECONDS)
            .subscribe(new Action1<List<Integer>>() {
                @Override
                public void call(List<Integer> integers) {
                    Log.i("TAG", String.valueOf(integers.size()));
                }
            });
}

@Override
protected void onPause() {
    super.onPause();
    mSubscription.unsubscribe();
}

OnClickListener簡単に言えば、メソッドの実装を閉じるだけで、その中でオブジェクトcallを使用できるようになります。subscriber

ラムダを使用onResumeするとさらに見栄えが良くなります(Retrolambda プロジェクトを見てください):

@Override
protected void onResume() {
    super.onResume();
    mSubscription = Observable.create((Subscriber<? super Integer> subscriber) ->
            findViewById(R.id.rx_button).setOnClickListener(view ->
                    subscriber.onNext(1))).buffer(2, TimeUnit.SECONDS)
            .subscribe(integers -> Log.i("TAG", String.valueOf(integers.size())));
}
于 2014-07-24T21:35:44.997 に答える