Reputation: 305
I'm trying to create an observable by chaining together multiple retrofit api calls. The steps are:
This is what I have so far:
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);
Could someone please confirm that I have used the correct operators. Thanks .
Upvotes: 6
Views: 4842
Reputation: 2927
Edit: Removed the Observable.create, retrofit is already making an observable for you, you merely need to transform it.
Edit 2: you also shouldn't need to do anything with subscriber.onError, if an error gets thrown it will call subscriber.onError on its own.
Pretty good, Not sure why you went with flatmap observable. I would instead do flatmap to Observable::from, also collect is worth adding. Basically I'm going to map 1 thing to many, then do some action, collect the many back into one and then subscribe to that one once I collected all items emitted.
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});
Upvotes: 2
Reputation: 1128
I think some like this should work for you. Instead of pulling in a Subject to emit it the DownloadedFile(s) to, you can just use the Observable from the REST service to map to each of the DownloadedFiles:
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));
}
});
}
You may want to consider using mergeDelayError(map()) instead of flatMap if you want to emit successfully saved files before propagating any errors.
Upvotes: 0