如何在RxAndroid 2.0中正确过滤/计数?

时间:2018-01-23 20:40:12

标签: android rx-java2 rx-android

给定一个存储库,返回一个可观察的账单清单:

Observable<List<Bill>> getBills();

我希望只有在未支付一张或多张账单时才能显示视图。我正在尝试以下代码:

repository.getBills()
    .flatMapIterable(bills -> bills)
    .filter(bill -> !bill.isPaid())
    .count()
    .map(count -> count > 0)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(overdue -> {
        if (!overdue) return;
        mView.showWarning();
    });

但是onSuccessonError都没有被调用。

我知道存储库至少包含一个过期项目,因为以下代码打印了未支付的账单:

repository.getBills()
    .subscribeOn(Schedulers.io())
    .flatMapIterable(bills -> bills)
    .filter(bill -> !bill.isPaid())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(
        bill -> Timber.d(bill.toString()),
        e -> Timber.e(e.getMessage(), e),
        () -> Timber.d("Completed")
    );

3 个答案:

答案 0 :(得分:2)

<强> TL; DR:
如果它永远不会完成,count无法正常工作。如果您要查看未付款的商品,可以使用any运营商,takeUntiltakeWhile。跳到这个答案中的第三个项目。

完整答案:

有三个可能的问题:

  1. 可能发生在showWarning()内。我运行了以下代码和 它打印DUE:

    findViewById(R.id.doSomething).setOnClickListener(v -> {
        clearWarning();
        getBills()
            .subscribeOn(Schedulers.io())
            .flatMapIterable(bills -> bills)
            .filter(bill -> !bill.isPaid())
            .count()
            .map(count -> count > 0)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                due -> {
                  if (!due) return;
                  showWarning();
                }
            );
    });
    

    使用以下getBills()

    private Observable<List<Bill>> getBills() {
        Bill sampleBill = new Bill();
        List<Bill> bills = new ArrayList<>(1);
        bills.add(sampleBill);
        return Observable.just(bills);
    }
    

    Bill是一个仅在false中返回isPaid()的虚拟类:

    class Bill {
        public boolean isPaid() {
            return false;
        }
    }
    

    TextViewshowWarning()clearWarning() getBills() 正确打印&#34;到期&#34;

  2. 另一个选项是onComplete()内的问题。是吗? 来源完成成功(我的意思是,它调用Single)?您可以手动拨打电话或使用toObservable(),但之后需要在flatMapIterable()之前致电getBills()

    根据documentation

      

    如果源Observable以错误终止,则Count将通过   此错误通知,而不首先发出项目。如果   源Observable根本不会终止,Count也不会发出   项目也不会终止。

  3. 如果您无法在takeWhile中更改Observable,只需要 检测何时有非付费账单,您可以使用takeUntilanyfindViewById(R.id.doSomething).setOnClickListener(v -> { clearWarning(); getBills() .flatMapIterable(bills -> bills) .takeUntil(bill -> !bill.isPaid()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( bill -> { Log.d("POTATO", "Number: " + bill.getNumber() + " Paid: " + bill.isPaid()); }, e -> Log.e("POTATO", "Error"), () -> { Log.d("POTATO", "Complete"); showWarning(); } ); }); }

    getBills()

    对于此示例,我将 private Observable<List<Bill>> getBills() { List<Bill> bills = new ArrayList<>(); bills.add(new Bill(1, true)); bills.add(new Bill(2, true)); bills.add(new Bill(3, false)); bills.add(new Bill(4, false)); return Observable.create( emitter -> emitter.onNext(bills) ); } 更改为永不完成:

    Bill

    要显示正在发出的项目,现在class Bill { private final int number; private boolean isPaid; Bill(int number, boolean isPaid) { this.number = number; this.isPaid = isPaid; } int getNumber() { return number; } boolean isPaid() { return isPaid; } } 类为 如下:

    Log

    showWarning()打印

    数量:1付费:真实 数量:2支付:真实 数量:3付:假
    完整

    然后调用takeWhile。当然,takeUntil的返回值应该与takeWhile相反。两者都会收取付费项目并在有未付款项目时停止,但Number: 3: Paid: false甚至不会发出未付款项目(any不会出现在日志中,但它会在2)之后立即完成。 unsubscribe会获得满足条件的任何项目,这对您来说可能已经足够了。请注意,这是一个完全不同的解决方案。如果源只发出付费项目,它将永远不会完成。但无论如何你应该在某个地方{{1}}。

答案 1 :(得分:1)

这是实际有效的完整示例。您可能在getBills方法中遇到问题。最常见的是缺少source.onComplete()电话。

    //...
    getBills()
            .flatMapIterable(bills -> bills)
            .filter(bill -> !bill.isPaid)
            .count()
            .map(count -> count > 0)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(this::onNext, this::onError);

public void onNext(boolean b) {
    Log.d("TAG", "Should show:" + b);
}

public void onError(Throwable throwable) {
    Log.d("TAG", throwable.getMessage());
}

public Observable<List<Bill>> getBills() {
    return Observable.create(source -> {
        try {
            List<Bill> bills = new ArrayList<>();
            bills.add(new Bill(true));
            bills.add(new Bill(true));
            bills.add(new Bill(false));
            bills.add(new Bill(false));
            source.onNext(bills);
            source.onComplete();
        }
        catch (Throwable throwable) {
            source.onError(throwable);
        }
    });
}

public static class Bill {
    public boolean isPaid;

    public Bill(boolean isPaid) {
        this.isPaid = isPaid;
    }
}

答案 2 :(得分:1)

如果您不需要计数,最好使用any运算符,如果源Observable发出的任何项满足指定条件,则运算为true,否则为false。

所以这段代码

.filter(bill -> !bill.isPaid())
.count()
.map(count -> count > 0).filter(bill -> !bill.isPaid())
.count()
.map(count -> count > 0)

应替换为

.any(bill -> !bill.isPaid())
某些版本的RxJava中的

警告任何运算符都可以命名为exists