RxJava - 两个Observable源,仅在某些值上组合输出

时间:2017-04-25 22:24:42

标签: android rx-java rx-binding

问题:

我应该使用哪种运算符或转换以最有效的方式以最少的代码组合两个数据流?

ViewPager,RxBinding,事件流

使用Android ViewPager,我观察事件(使用RxBinding)

1)OnPageSelected(当前页面可见)

Observable<Integer> pageSelectObs = RxViewPager.pageSelections(mPlaceImageViewPager);

2)OnPageScrollStateChanged(滑动起始= 1,运动= 2,完成= 0)

Observable<Integer> scrollStateObs = RxViewPager.pageScrollStateChanges(mPlaceImageViewPager);

整数流看起来像这样:

I/System.out: Page: 0 ScrollState: 1
I/System.out: Page: 0 ScrollState: 2
I/System.out: Page: 1 ScrollState: 2
I/System.out: Page: 1 ScrollState: 0
I/System.out: Page: 1 ScrollState: 1
I/System.out: Page: 1 ScrollState: 2
I/System.out: Page: 2 ScrollState: 2
I/System.out: Page: 2 ScrollState: 0

我只对以下情况感兴趣:

  • ScrollState == 0
  • 到达ViewPager的结尾

当前代码

这就是我目前观察的方式:

Disposable d = ObservableCombineLatest.combineLatest(pageSelectObs, scrollStateObs, new BiFunction<Integer, Integer, Integer>() {
    @Override
    public Integer apply(@NonNull Integer pageSelected, @NonNull Integer scrollState) throws Exception {
        AUtils.logSystem(TAG, "Page: %s ScrollState: %s", pageSelected, scrollState);

        if (adapter.isLastVisibleItem(pageSelected) && adapter.hasHiddenItemsRight() && scrollState == 0) {
            return 1;
        }

        if (adapter.isFirstVisibleItem(pageSelected) && adapter.hasHiddenItemsLeft() && scrollState == 0) {
            return -1;
        }
        return 0;
    }
}).subscribe(new Consumer<Integer>() {
    @Override
    public void accept(@NonNull Integer doAction) throws Exception {
        if (doAction == -1) {
            AUtils.logSystem(TAG, "shift LEFT");
            adapter.shiftLeft();
        }
        if (doAction == 1) {
            AUtils.logSystem(TAG, "shift RIGHT");
            adapter.shiftRight();
        }
    }
});

有更简单的方法吗?

2 个答案:

答案 0 :(得分:1)

由于条件非常简单,您可以使用简单的filter()运算符表达它们。

Observable<Integer> scrollStateObs = RxViewPager.pageScrollStateChanges(mPlaceImageViewPager)
        .filter(scrollState -> scrollState == ViewPager.SCROLL_STATE_IDLE);

为了仅对scrollState更改做出反应,您可以使用withLatestFrom()运算符

Disposable d = pageSelectObs.withLatestFrom(scrollStateObs, (pageSelected, scrollState) -> pageSelected)
        .filter(pageSelected -> adapter.isLastVisibleItem(pageSelected));
        .subscribe(pageSelected -> {
            if (adapter.hasHiddenItemsRight()) {
                adapter.shiftRight();
            } else if (adapter.hasHiddenItemsLeft()) {
                adapter.shiftRight();
            }
        });

答案 1 :(得分:0)

嗯,最有效的方式&#39;取决于您的要求以及您如何定义最有效率。是时候了,是资源吗?

我拿了你的代码并添加了一个50毫秒的速率限制窗口,突发事件不会经常调用onNext。

在MAP-opreator中,你会为枚举添加一些匹配,因为-1和1不是代表值。

@Test
void name() throws Exception {
    Observable<Integer> pageSelectObs = Observable.just(0, 0, 1, 1, 1, 1, 2, 2);
    Observable<Integer> scrollStateObs = Observable.just(1, 2, 2, 0, 1, 2, 2, 0);

    // Test-Obs
    Observable<ShiftOperation> filter = Observable.combineLatest(pageSelectObs, scrollStateObs, Combined::new)
            .window(50, TimeUnit.MILLISECONDS)
            .flatMap(combinedObservable -> combinedObservable.filter(combined -> combined.scrollState == 0)
                    .takeLast(1))
            .map(combined -> {
                // do mapping here

                return ShiftOperation.SHIFT_LEFT; // do your adapter... check here and decide which operation you want to return.
            });

    filter.test()
            .await()
            .assertValueCount(1);
}

数据结构:

class Combined {
    final int pageState;
    final int scrollState;

    Combined(int pageState, int scrollState) {
        this.pageState = pageState;
        this.scrollState = scrollState;
    }
}

enum ShiftOperation {
    SHIFT_LEFT,
    SHIFT_RIGHT
}