如何使用RxJava遍历列表并在第一项上执行初始过程

时间:2019-02-03 18:23:24

标签: rx-java2

我是RxJava的新手,发现它对我的Android应用程序中的网络和数据库处理非常有用。

我有两个无法完全在RxJava中实现的用例

用例1

  1. 清除目标数据库表Table A
  2. 从表B中获取包含关键字段的数据库记录列表
  3. 对于从表B检索到的每一行,调用远程API并将所有返回的数据持久保存在表A中

我管理的最接近的代码是

final AtomicInteger id = new AtomicInteger(0);

DatabaseController.deleteAll(TableA_DO.class);

DatabaseController.fetchTable_Bs()
        .subscribeOn(Schedulers.io())
        .toObservable()
        .flatMapIterable(b -> b)
        .flatMap(b_record -> NetworkController.getTable_A_data(b_record.getKey()))
        .flatMap(network -> transformNetwork(id, network, NETWORK_B_MAPPER))
        .doOnNext(DatabaseController::persistRealmObjects)
        .doOnComplete(onComplete)
        .doOnError(onError)
        .doAfterTerminate(doAfterTerminate())
        .doOnSubscribe(compositeDisposable::add)
        .subscribe();

用例2

  1. 清除我的目标数据库表Table X
  2. 清除目标数据库表Table Y
  3. 从表Z中获取包含关键字段的数据库记录列表
  4. 对于从表B检索到的每一行,调用远程API并将某些返回的数据持久化到表X中,其余数据应持久化到表Y中

我还没有为用例2创建任何代码。

对于在这些用例中使用RxJava,我有很多疑问。

  1. 是否可以在RxJava中实现两个用例?
  2. 将所有这些步骤组合到Rx“流”中是否是“最佳实践”

更新

我最终得到了这个似乎有效的POC测试代码... 我不确定它是否是最佳解决方案,但是我的API调用返回Single,而我的数据库操作返回Completable,所以我觉得这对我来说是最佳解决方案。

public class UseCaseOneA {

    public static void main(final String[] args) {

        login()
        .andThen(UseCaseOneA.deleteDatabaseTableA())
        .andThen(UseCaseOneA.deleteDatabaseTableB())
        .andThen(manufactureRecords())
            .flatMapIterable(x -> x)
            .flatMapSingle(record -> NetworkController.callApi(record.getPrimaryKey()))
            .flatMapSingle(z -> transform(z))
            .flatMapCompletable(p -> UseCaseOneA.insertDatabaseTableA(p))
            .doOnComplete(() -> System.out.println("ON COMPLETE"))
            .doFinally(() -> System.out.println("ON FINALLY"))
            .subscribe();

    }

    private static Single<List<PayloadDO>> transform(final List<RemotePayload> payloads) {
        return Single.create(new SingleOnSubscribe<List<PayloadDO>>() {
            @Override
            public void subscribe(final SingleEmitter<List<PayloadDO>> emitter) throws Exception {
                System.out.println("transform - " + payloads.size());

                final List<PayloadDO> payloadDOs = new ArrayList<>();

                for (final RemotePayload remotePayload : payloads) {
                    payloadDOs.add(new PayloadDO(remotePayload.getPayload()));
                }

                emitter.onSuccess(payloadDOs);
            }
        });
    }

    private static Observable<List<Record>> manufactureRecords() {
        final List<Record> records = new ArrayList<>();
        records.add(new Record("111-111-111"));
        records.add(new Record("222-222-222"));
        records.add(new Record("3333-3333-3333"));
        records.add(new Record("44-444-44444-44-4"));
        records.add(new Record("5555-55-55-5-55-5555-5555"));

        return Observable.just(records);
    }

    private static Completable deleteDatabaseTableA() {

        return Completable.create(new CompletableOnSubscribe() {

            @Override
            public void subscribe(final CompletableEmitter emitter) throws Exception {
                System.out.println("deleteDatabaseTableA");

                emitter.onComplete();
            }
        });
    }

    private static Completable deleteDatabaseTableB() {

        return Completable.create(new CompletableOnSubscribe() {

            @Override
            public void subscribe(final CompletableEmitter emitter) throws Exception {
                System.out.println("deleteDatabaseTableB");

                emitter.onComplete();
            }
        });
    }

    private static Completable insertDatabaseTableA(final List<PayloadDO> payloadDOs) {
        return Completable.create(new CompletableOnSubscribe() {
            @Override
            public void subscribe(final CompletableEmitter emitter) throws Exception {
                System.out.println("insertDatabaseTableA - " + payloadDOs);

                emitter.onComplete();
            }
        });
    }

    private static Completable login() {
        return Completable.complete();
    }
}

此代码不能满足我所有的用例要求。即能够将远程有效负载记录转换为多种数据库记录类型,并将每种类型插入其自己的特定目标数据库表中。

我可以两次调用Remote API来获取相同的远程数据项,然后先转换为一种数据库类型,然后再转换为第二种数据库类型,但这似乎很浪费。

RxJava中是否有一个操作数,我可以在其中重用API调用的输出并将其转换为另一种数据库类型?

1 个答案:

答案 0 :(得分:1)

您必须自己以某种方式为项目建立索引,例如,通过外部计数:

Observable.defer(() -> {
    AtomicInteger counter = new AtomicInteger();

    return DatabaseController.fetchTable_Bs()
        .subscribeOn(Schedulers.io())
        .toObservable()
        .flatMapIterable(b -> b)
        .doOnNext(item -> {
            if (counter.getAndIncrement() == 0) {
                // this is the very first item
            } else {
                // these are the subsequent items
            }
        });
});

必须使用defer才能将计数器与内部序列隔离开,以便在必要时仍可以重复。