Retrofit 2 + RxJava 将类似的请求干净地链接在一起
Retrofit 2 + RxJava chaining similar requests together cleanly
目标
在我的应用程序中,我希望使用 Retrofit 2 将一些文件上传到我的网络服务器(一次多个文件,在本例中为图片。)并且在每个文件上传完成后我想更新一个 SQL table 与该特定文件的路径。
尝试过
我是函数式编程范式的新手,所以我的理解在这里可能会被误导。我有两个不同的对象,一个 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 列表合并在一起,以便我对它们中的每一个执行相同的操作。在这种情况下,Observables 是 FileResponse 类型。这是上传到文件的网络服务。
map ( ) - 通过对每个项目应用函数来转换 Observable 发出的项目。
在这种情况下,我想对 FileResponse Observables 应用一个函数,returns 一个新的 Observable,Observable。
forEach( ) — 对 Observable 发出的每个项目调用一个函数;阻塞直到 Observable 完成。
然后这将获取每个发出的 Observable 并上传它。但是在这种情况下,这部分失败了。文件成功上传,但 forEach 部分只是 returns "Error: null"。
问题
这种理解是否接近我想要达到的目标?同样,我只是希望将多个请求链接在一起,在其他请求成功时执行新请求。有更好/正确的方法吗?
编辑备注:
我忘了说,我可以这样实现我想要的:
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!!");
}
});
}
}
);
但我试图找到一种可能更简洁的方法来执行此操作。如果这是唯一的方法,那就够公平了。只是想就我的想法获得更多意见,看看我可以做些什么来让它看起来更好(或最佳实践)。
为了使其更简洁(并避免额外订阅 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
个对象(与 map()
之后的 Observable<Photo>
相比)。
目标
在我的应用程序中,我希望使用 Retrofit 2 将一些文件上传到我的网络服务器(一次多个文件,在本例中为图片。)并且在每个文件上传完成后我想更新一个 SQL table 与该特定文件的路径。
尝试过
我是函数式编程范式的新手,所以我的理解在这里可能会被误导。我有两个不同的对象,一个 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 列表合并在一起,以便我对它们中的每一个执行相同的操作。在这种情况下,Observables 是 FileResponse 类型。这是上传到文件的网络服务。
map ( ) - 通过对每个项目应用函数来转换 Observable 发出的项目。
在这种情况下,我想对 FileResponse Observables 应用一个函数,returns 一个新的 Observable,Observable。
forEach( ) — 对 Observable 发出的每个项目调用一个函数;阻塞直到 Observable 完成。
然后这将获取每个发出的 Observable 并上传它。但是在这种情况下,这部分失败了。文件成功上传,但 forEach 部分只是 returns "Error: null"。
问题
这种理解是否接近我想要达到的目标?同样,我只是希望将多个请求链接在一起,在其他请求成功时执行新请求。有更好/正确的方法吗?
编辑备注:
我忘了说,我可以这样实现我想要的:
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!!");
}
});
}
}
);
但我试图找到一种可能更简洁的方法来执行此操作。如果这是唯一的方法,那就够公平了。只是想就我的想法获得更多意见,看看我可以做些什么来让它看起来更好(或最佳实践)。
为了使其更简洁(并避免额外订阅 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
个对象(与 map()
之后的 Observable<Photo>
相比)。