RxJava / Retrofit2 / Java-NetworkBoundResource无法按预期工作

时间:2019-03-17 01:52:11

标签: java android rx-java rx-java2 rx-android

我遇到了一些有线问题。当我第一次订阅时,它会进行网络调用并将数据保存到数据库中,但是loadFromDb()从未执行过,也没有抛出任何错误。

为什么会这样?

    Flowable<Resource<List<List<DataSource>>>> getBoundResource(List<String> parentId) {
    return new RxNetworkBoundResource<List<List<DataSource>>,
            ContainerResponse>() {
        @Override
        void saveCallResult(@NonNull List<ContainerResponse> data) {
            for (ContainerResponse item : data) {
                // Saves data to database
                List<DataSource> items = item.items;
                containerDao.insert(items);
            }
        }

        @Override
        protected Flowable<List<List<DataSource>>> loadFromDb() {
            return Flowable.just(parentId).flatMapIterable(d -> d)
                    .flatMap(s -> containerDao.loadContainerByParentIdRx(s))
                    .distinct()
                    .doOnNext(data -> {
                        // I am able to get data here
                    })
                    .toList() // I'm not able to get data after toList()
                    .toFlowable()
                    .doOnNext(data -> {
                        // Nothing here
                    });
        }

        @Override
        protected Flowable<List<Response<ContainerResponse>>> createCall() {
            String baseUrl =
                    MyApp.getApplication().getSharedConfig().getBaseUrl();
            return Flowable.just(parentId).flatMapIterable(data -> data).flatMap(s -> {
                String url = baseUrl + "?limit=30&offset=0&parent=" + s;
                return Flowable.zip(Flowable.just(s),webservice.getContainersBoundRx(url),
                        (s1, response) -> {
                            if (response.body() == null) {
                                return response;
                            }
                            for (DataSource container : response.body().items) {
                                container.parentId = s1;
                            }
                            return response;
                        }).toList().toFlowable();
            });
        }

        @Override
        protected boolean shouldFetch() {
            return false;
        }
    }.asFlowable();

subscribe()之后我什么也没得到。

    containerRepo.getBoundResource(parentId)
            .subscribe(new Subscriber<Resource<List<List<DataSource>>>>() {
                @Override
                public void onSubscribe(Subscription s) {

                }

                @Override
                public void onNext(Resource<List<List<DataSource>>> listResource) {
                   // No data
                }

                @Override
                public void onError(Throwable t) {

                }

                @Override
                public void onComplete() {
                    // This is never called
                }
            });

NetworkboundResource类:

public abstract class RxNetworkBoundResource<ResultType, RequestType> {

private final String TAG = RxNetworkBoundResource.class.getSimpleName();

private Flowable<Resource<ResultType>> result;

RxNetworkBoundResource() {
    // Lazy db observable.
    Flowable<ResultType> dbObservable =
            Flowable.defer(() -> loadFromDb().subscribeOn(Schedulers.computation()));

    // Lazy network observable.
    Flowable<ResultType> networkObservable = Flowable.defer(() ->
            createCall()
                    .subscribeOn(Schedulers.io())
                    .observeOn(Schedulers.computation())
                    .doOnNext(request -> {
                        if (request.get(0).isSuccessful()) {
                            saveCallResult(processResponse(request));
                        } else {
                            processInternalError(request);
                        }
                    })
                    .onErrorReturn(throwable -> {
                        throw Exceptions.propagate(throwable);
                    })
                    .flatMap(__ -> loadFromDb())
    );

    result = shouldFetch()
            ? networkObservable
            .map(Resource::success)
            .onErrorReturn(t -> Resource.error(t.getMessage(), null))
            .observeOn(AndroidSchedulers.mainThread())
            : dbObservable
            .map(Resource::success)
            .onErrorReturn(t -> Resource.error(t.getMessage(), null))
            .observeOn(AndroidSchedulers.mainThread())
    ;
}

Flowable<Resource<ResultType>> asFlowable() {
    return result;
}

private List<RequestType> processResponse(List<Response<RequestType>> response) {
    List<RequestType> list = new ArrayList<>();
    for (Response<RequestType> data : response) {
        list.add(data.body());
    }
    return list;
}

private void processInternalError(List<Response<RequestType>> response) throws java.io.IOException {
    for (Response<RequestType> data : response) {
        if (data.errorBody() != null) {
            String error = data.errorBody().string();
            throw Exceptions.propagate(new Throwable(data.code() + ": " + error));
        }
    }
}

abstract void saveCallResult(@NonNull List<RequestType> item);

abstract Flowable<ResultType> loadFromDb();

abstract Flowable<List<Response<RequestType>>> createCall();

abstract boolean shouldFetch();

}

1 个答案:

答案 0 :(得分:0)

请注意,.toList()仅在其上游完成后才会发出。 Doc

这里的问题很可能是由于此代码返回的Flowable未完成:

containerDao.loadContainerByParentIdRx(s)

如果此Flowable从未完成,那么生成的flatMap也将不会完成,并且toList()将不会发出任何东西。

如果仅查找数据库一次,则一种选择是将返回类型更改为SingleMaybe。例如,如果您切换到Maybe,则可以执行以下操作:

    @Override
    protected Flowable<List<List<DataSource>>> loadFromDb() {
        return Flowable.just(parentId).flatMapIterable(d -> d)
                .flatMapMaybe(s -> containerDao.loadContainerByParentIdRx(s))
                .distinct()
                .doOnNext(data -> {
                    // I am able to get data here
                })
                .toList() // You should now get this as well.
                .toFlowable()
                .doOnNext(data -> {
                    // Nothing here
                });
    }