RxJava flatMapIterable с concatMap
У меня есть 2 звонка для модернизации, которые мне нужны для A & B:
(A): возвращает ArrayList
(B): получает результат (A), который является ArrayList. (B) перебирает ArrayList и выполняет вызов дооснащения, используя каждый из них, и объединяет полученные данные в окончательный ArrayList, который отправляется моему подписчику onNext()
Мне удалось заставить его работать с flatmap, но решение не очень элегантное. Насколько я понимаю, лучшим решением было бы использование flatMapIterable с concatMap, но я не могу принять то, что у меня работает, для flatMapIterable с concatMap.
ServiceFactory.createRetrofitService().getUserFollowing(sessionMgr.getAuthToken())
.flatMap(new Func1<UserSelfFollows, Observable<? extends ArrayList<Media.MediaData>>>() {
@Override
public Observable<? extends ArrayList<Media.MediaData>> call(UserSelfFollows userSelfFollows) {
//make second requests based on response from First request to get all Users
ArrayList<Media.MediaData> arAllMedia = new ArrayList<>();
for(UserSelfFollows.UserDataFollows user : userSelfFollows.userdata){
Response <ResponseBody> response ;
Call <ResponseBody> call;
try {
call = ServiceFactory.createRetrofitService().getMediaOfUser(user.id,sessionMgr.getAuthToken());
response = call.execute();
}catch(IOException ex){
return Observable.error(ex);
}
if (response.isSuccessful()) {
try {
String str = responseHelper.streamToString( response.body().byteStream());
Gson gson = new GsonBuilder().create();
Media media = gson.fromJson(str, Media.class);
arAllMedia.addAll(media.mediaData);
} catch (IOException e) {
return Observable.error(e);
}
} else {
return Observable.error( new Exception( responseHelper.getErrorString( response.errorBody().byteStream())) );
}
}
return Observable.just(arAllMedia);
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<ArrayList<Media.MediaData>>() {
@Override
public final void onCompleted() {
}
@Override
public final void onError(Throwable e) {
}
@Override
public final void onNext(ArrayList<Media.MediaData> arMedia) {
}
})
Вот что у меня есть, но оно не скомпилируется:
ServiceFactory.createRetrofitService().getUserFollowing(sessionMgr.getAuthToken())
.flatMapIterable(new Func1<UserSelfFollows, Iterable<?>>() {
@Override
public Iterable<?> call(UserSelfFollows userSelfFollows) {
return userSelfFollows.userdata;
}
})
.<Media.MediaData>flatMap(new Func1<UserSelfFollows.UserDataFollows, Observable<Media.MediaData>>() {
@Override
public Observable<Media.MediaData> call(UserSelfFollows.UserDataFollows user) {
return ServiceFactory.createRetrofitService().getMediaOfUser(user.id, sessionMgr.getAuthToken());
}
})
.toList();
Ошибка:
3 ответа
Если я правильно понимаю ваш сценарий, вы можете использовать flatMapIterable
, а потом flatMap
операторы, в конце собирают все результаты вызовов дооснащения с toList
,
Во-первых flatMapIterable
вы льете UserDataFollows
Список вы получите с первого звонка (getUserFollowing()
) в Obsevrable, который испускает несколько элементов из этого списка, затем flatMap
создать Observable
что делает призыв к модернизации для каждого UserSelfFollows.UserDataFollows
объект данных, (это будет происходить параллельно, что кажется больше подходит здесь, но вы также можете использовать concatMap
если вы заинтересованы в последовательном выполнении), то собрать все окончательные данные вместе, как список MediaData
объекты, вы можете использовать toList
ServiceFactory.createRetrofitService().getUserFollowing(sessionMgr.getAuthToken())
.flatMapIterable(new Func1<UserSelfFollows, Iterable<?>>() {
@Override
public Iterable<?> call(UserSelfFollows userSelfFollows) {
return userSelfFollows.userdata;
}
})
.flatMap(new Func1<UserSelfFollows, Observable<Media>>() {
@Override
public Observable<Media> call(UserSelfFollows user) {
return ServiceFactory.createRetrofitService().getMediaOfUser(user.id, sessionMgr.getAuthToken());
}
})
.toList()
.subscribe(new Action1<List<Media>>() {
@Override
public void call(List<Media> rs) {
//do something with the list of media data
}
});
Я никогда не использовал оба flatMapIterable
или же concatMap
, но в качестве альтернативного решения вы могли бы использовать flatMap
а также compose
оператор:
ServiceFactory.createRetrofitService().getUserFollowing(sessionMgr.getAuthToken())
.flatMap(list -> Observable.from(list))
.compose(getComposer())
.subscribe(mediaData -> mMediaDataList.add(mediaData), throwable -> {}, () -> { // on complete do something with mMediaList});
куда getComposer()
возвращает Трансформер UserSelfFollows
-> Media.MediaData
protected Observable.Transformer<UserSelfFollows, Media.MediaData> getComposer() {
return ;
}
Ответ Йосриза направил меня в правильном направлении. Поэтому, чтобы другие не потянулись за этим, вот ПОЛНОЕ кодовое решение:
ServiceFactory.createRetrofitService().getUserFollowing(sessionMgr.getAuthToken())
.flatMapIterable(new Func1<UserSelfFollows, Iterable<UserSelfFollows.UserDataFollows>>() {
@Override
public Iterable< UserSelfFollows.UserDataFollows > call(UserSelfFollows userSelfFollows) {
return userSelfFollows.userdata;
}
})
.flatMap(new Func1<UserSelfFollows.UserDataFollows, Observable<Media>>() {
@Override
public Observable<Media> call(UserSelfFollows.UserDataFollows user) {
return ServiceFactory.createRetrofitService().getMediaOfUser(user.id, sessionMgr.getAuthToken());
}
})
.toList()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<Media>>() {
@Override
public final void onCompleted() {
}
@Override
public final void onError(Throwable e) {
userMessageHandler.showDialog(mParentActivity, mParentActivity.getString(R.string.error_retrieving_data_title),
mParentActivity.getString(R.string.error_self_following_media) + e.getMessage(), 0);
}
@Override
public final void onNext(List<Media> arMedia) {
if (arMedia.size() == 0)
userMessageHandler.showToast(mParentActivity, mParentActivity.getString(R.string.warn_no_following));
else {
ArrayList<Media.MediaData> allMedia = new ArrayList<>();
for(Media media : arMedia){
allMedia.addAll(media.mediaData);
}
mBinding.gridview.setAdapter(new MediaGridViewAdapter(mParentActivity,FollowingViewModel.this, allMedia));
}
}
});