在Flowable中收集2个并行发布者的结果

时间:2017-04-06 16:12:05

标签: android rx-java reactive-programming rx-android

我对反应式编程很新,但尝试应用rxjava来收集调用和短信列表并合并为单个。这个想法是以顺序方式迭代光标,顺序项发射。 在此之后,所有项目都被收集到单个列表中。

但是在doOnComplete并非所有数据都被收集(我有大约150个项目,而且只有~25个被添加)。 我认为问题是Flowable.concat并不等待所有项目,但这只是一个建议。

public void readLatestActivity() {
    Cursor callsCursor = getCallsCursor();
    Cursor smsCursor = getSmsCursor();

    if (callsCursor == null || smsCursor == null) {
        return;
    }

    SortedSet<MActivity> activities = new TreeSet<>((left, right) -> left.getReceiveTime() < right.getReceiveTime() ? 1 : 0);

    Flowable.concat(getCallsPublisher(callsCursor), getSmsPublisher(smsCursor))
            .subscribeOn(Schedulers.io())
            .doOnNext(new Consumer<MActivity>() {
                @Override
                public void accept(@NonNull MActivity mActivity) throws Exception {
                    if (mActivity != null){
                        activities.add(mActivity);
                    }
                }
            })
            .observeOn(AndroidSchedulers.mainThread())
            .doOnComplete(new Action() {
                @Override
                public void run() throws Exception {
                    Timber.d("doOnComplete");
                    callsCursor.close();
                    smsCursor.close();
                    mBus.post(new EActivities(activities)); //<--- here I'm getting ~25 items
                }
            })
            .subscribe();
}

private Publisher<MActivity> getCallsPublisher(Cursor callsCursor) {
    return Flowable.fromIterable(RxCursorIterable.from(callsCursor))
            .take(callsCursor.getCount() < LIMIT ? callsCursor.getCount() : LIMIT)
            .subscribeOn(Schedulers.computation())
            .parallel()
            .runOn(Schedulers.computation())
            .map((Function<Cursor, MActivity>) this::readCallFromCursor)
            .sequential()
            .observeOn(AndroidSchedulers.mainThread());

}

private Publisher<MActivity> getSmsPublisher(Cursor smsCursor) {
    return Flowable.fromIterable(RxCursorIterable.from(smsCursor))
            .take(smsCursor.getCount() < LIMIT ? smsCursor.getCount() : LIMIT)
            .subscribeOn(Schedulers.computation())
            .parallel()
            .runOn(Schedulers.computation())
            .map((Function<Cursor, MActivity>) this::readSmsFromCursor)
            .sequential()
            .observeOn(AndroidSchedulers.mainThread());
}

读取短信和通话工作正常的方法。我认为问题出在其他地方。

此外,我发现了一个使cursor行为像Iterable

的课程
public class RxCursorIterable implements Iterable<Cursor> {

private Cursor mIterableCursor;

public RxCursorIterable(Cursor c) {
    mIterableCursor = c;
}

public static RxCursorIterable from(Cursor c) {
    return new RxCursorIterable(c);
}

@Override
public Iterator<Cursor> iterator() {
    return RxCursorIterator.from(mIterableCursor);
}

private static class RxCursorIterator implements Iterator<Cursor> {

    private final Cursor mCursor;

    public RxCursorIterator(Cursor cursor) {
        mCursor = cursor;
    }

    public static Iterator<Cursor> from(Cursor cursor) {
        return new RxCursorIterator(cursor);
    }

    @Override
    public boolean hasNext() {
        return !mCursor.isClosed() && mCursor.moveToNext();
    }

    @Override
    public Cursor next() {
        return mCursor;
    }
}
}

1 个答案:

答案 0 :(得分:1)

我认为问题在于您在创建TreeSet时使用的比较器。 -1时,它不会返回left.getReceiveTime() > right.getReceiveTime(),即某些活动被错误地视为重复。

我还建议您简化getCallsPublisher代码:

return Flowable.generate(getCallsCursor(),
        (cursor, emitter) -> {
            if (!cursor.isClosed() && cursor.moveToNext())
                emitter.onNext(readCallFromCursor(cursor));
            else
                emitter.onComplete();
        }, Cursor::close)
    .take(LIMIT);

摆脱RxCursorIterable