Retrofit 2 + RxJava干净地将类似的请求链接在一起

时间:2016-03-18 23:55:58

标签: android rest rx-java retrofit2

目标

在我的应用程序中,我希望使用Retrofit 2将一些文件上传到我的Web服务器(一次多个,在这种情况下是图片)。完成每个文件的上传后,我想用一个SQL表来更新该特定文件的路径。

试过

我是使用函数式编程范例的新手,所以我的理解可能会在这里误导。我有两个不同的对象,一个FileResponse(DTO代表文件上传后我的Web服务器的响应)和一个Photo对象。此Photo对象有两个字段,并充当在我的后端服务器中持久存在的实体。它的字段对应于列,并且单独上传这些对象中的每一个都可以正常工作。我试图做的是在一次扫描中进行这种双重操作。

以下是我的尝试:

List<Observable<FileResponse>> mObservables = new ArrayList<>(3);

...
...

Observable.merge(mObservables).
            map(new Func1<FileResponse, Observable<Photo>>() {
                @Override
                public Observable<Photo> call(FileResponse fileResponse) {
                    Photo photo = new Photo();
                    photo.setPath(fileResponse.getUrl());
                    photo.setId("demo123");
                    return mPhotoService.createPhoto(photo);
                }
            }).forEach(
                new Action1<Observable<Photo>>() {
                    @Override
                    public void call(Observable<Photo> photoObservable) {

                    }
                },
                new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        Log.e(TAG, "Error: " + throwable.getMessage());
                    }
                }
            );

这是我背后的逻辑:

merge() - 将多个Observable合并为一个。

我希望我创建的Observable列表合并在一起,所以我对它们中的每一个都执行相同的操作。在这种情况下,Observable的类型为FileResponse。这是上传到文件Web服务。

map() - 通过将函数应用于每个项目来转换Observable发出的项目。

在这种情况下,我想将一个函数应用于FileResponse Observables,它返回一个新的Observable,Observable。

forEach() - 在Observable发出的每个项目上调用一个函数;阻止直到Observable完成。

然后,这将采用每个发出的Observable并上传它。但在这种情况下,这部分失败了。文件成功上传,但forEach部分只返回&#34;错误:null&#34;。

问题

这种理解是否接近我想要实现的目标?同样,我只希望将多个请求链接在一起,在其他请求成功时执行新请求。有没有更好/更正确的方法呢?

编辑注意:

我忘了提及,我能够达到我想要的目的:

Observable.merge(mObservables)
            .map(new Func1<FileResponse, Observable<Photo>>() {
                @Override
                public Observable<Photo> call(FileResponse fileResponse) {
                    Photo photo = new Photo();
                    photo.setPath(fileResponse.getUrl());
                    photo.setDogId("123");
                    return mPhotoService.createPhoto(photo);
                }
            })
           .subscribe(new Subscriber<Observable<Photo>>() {
                    @Override
                    public void onCompleted() {
                        Log.d(TAG, "Save complete!");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG, "Error: " + e.getMessage());
                    }

                    @Override
                    public void onNext(Observable<Photo> photoObservable) {
                        photoObservable.subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread())
                                .subscribe(new Subscriber<Photo>() {
                                    @Override
                                    public void onCompleted() {
                                        Log.d(TAG, "Here!");
                                    }

                                    @Override
                                    public void onError(Throwable e) {
                                        Log.d(TAG, "Error! " + e.getMessage());
                                    }

                                    @Override
                                    public void onNext(Photo photo) {
                                        Log.d(TAG, "Woo!!");
                                    }
                                });
                    }
                }
            );

但我试图找到一种可能更清洁的方法来做到这一点。如果这是唯一的方式,那就足够了。只是想获得更多关于我在想什么的意见,看看我能做些什么来使它看起来更好(或最佳实践)。

1 个答案:

答案 0 :(得分:2)

为了使其更清晰(并避免额外订阅onNext中的项目),您可以切换map() flatMap()

Observable.merge(mObservables)
                .flatMap(new Func1<FileResponse, Observable<Photo>>() {
                    @Override
                    public Observable<Photo> call(FileResponse fileResponse) {
                        Photo photo = new Photo();
                        return mPhotoService.createPhoto(photo);
                    }
                })
                .forEach(new Action1<Photo>() {
                    @Override
                    public void call(Photo photo) {

                    }
                });

正如您在代码段中看到的那样,flatMap之后的下一个运算符将会看到Photo个对象(仅在Observable<Photo>之后与map()进行比较)。