使用RxJava + Retrofit为列表中的每个项目发出API请求

时间:2015-04-19 15:52:57

标签: java android retrofit rx-java rx-android

我正在尝试通过将多个改装api调用链接在一起来创建一个observable。步骤是:

  1. 使用api call
  2. 获取json对象列表
  3. 对于列表中的每个对象,再次进行api调用以获取有关该项目的更多详细信息
  4. 将从这个新的详细对象中获取的数据写入磁盘上的文件(对于列表中的每个项目都会发生这种情况)
  5. 最后返回一个单独的对象的observable,该对象需要为每个先前的对象创建一个文件
  6. 这是我到目前为止所做的:

    public static Observable<DownloadedFiles> downloadFiles() {
        DownloadedFiles downloadedFiles = new DownloadedFiles();
        Observable.create(subscriber -> {
            return getRestService().getObjectList()
            .flatMapIterable(objects -> objects)
            .flatMap(objectLimited -> getRestService().getObject(objectLimited.getPath()))
            .doOnNext(objectFull -> {
    
                try {
                    File file = new File();
                    // Extract data from objectFull and write new file to disk
                    // ...
                    } catch (IOException e) {
                    subscriber.onError(e);
                }
    
                downloadedFiles.putFile(file);
            })
            .toList()
            .map(objects -> downloadedFiles)
            .finallyDo(() -> {
                subscriber.onNext(downloadedFiles);
                subscriber.onCompleted();
            });
        });
    }
    
    @GET("/api/...")
    Observable<List<Object>> getObjectList();
    
    @GET("/api/.../{path}")
    Observable<Object> getObject(@Path("path") String path);
    

    有人可以确认我使用了正确的操作符。谢谢。

2 个答案:

答案 0 :(得分:2)

编辑:删除了Observable.create,改造已经为你做了一个可观察的,你只需要改造它。

编辑2:你也不需要对subscriber.onError做任何事情,如果抛出错误,它将自己调用subscriber.onError。

非常好,不确定为什么你选择了flatmap observable。我宁愿做平面图到Observable :: from,也值得添加。基本上我会将1个事物映射到很多,然后做一些动作,将许多东西收回到一个,然后在收集所有发出的物品后订阅那个。

public static Observable<DownloadedFiles> downloadFiles() {        
        return getRestService().getObjectList()
        .flatMap(Observable::from)
        .flatMap(objectLimited -> getRestService().getObject(objectLimited.getPath()))
        .doOnNext(objectFull -> {
            try {
                File file = new File();
                // Extract data from objectFull and write new file to disk
                // ...
            } catch (IOException e) {
                new IOException(e);
            }})
      .collect(() -> new DownloadFiles<>(), (files, object) -> {  files.add(object});

答案 1 :(得分:0)

我认为这样的一些应该适合你。您可以使用REST服务中的Observable映射到每个DownloadedFiles,而不是拉入Subject以将其发送到DownloadedFile:

public static Observable<DownloadedFile> downloadFiles() {
    final Observable<Observable<FullObject>> observable =  getRestService().getObjectList()
            .flatMapIterable(objects -> objects)
            .map(objectLimited -> getRestService().getObject(objectLimited.getPath()));

    return  Observable.mergeDelayError(observable)
            .map(fullObject -> {
                try {
                    File file = new File("path");
                    // Extract data from objectFull and write new file to disk
                    // ...

                    return new DownloadedFile();
                } catch (IOException e) {
                    throw OnErrorThrowable.from(OnErrorThrowable.addValueAsLastCause(e, fullObject));
                }
            });
}

如果要在传播任何错误之前发出成功保存的文件,您可能需要考虑使用mergeDelayError(map())而不是flatMap。