Reputation: 6117
I have 2 retrofit calls I need to make A & B:
(A): returns an ArrayList
(B): gets the result of (A) which is an ArrayList. (B) iterates through the ArrayList and makes a retrofit call using each and combines the resulting data into a final ArrayList that is sent to my subscriber onNext()
I was able to get it working with flatmap, but the solution is not very elegant. As I understand it, a better solution would be to use flatMapIterable with concatMap but I can't seem to adopt what I have working to flatMapIterable with 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) {
}
})
Here is what I have so far, but it won't compile:
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();
The error is:
Upvotes: 2
Views: 2065
Reputation: 10267
If I understand correctly your scenario you can use flatMapIterable
, and then flatMap
operators, at the end collect all the retrofit calls result with toList
.
In the first flatMapIterable
you're flatting the UserDataFollows
List you get from the first call (getUserFollowing()
) to an Obsevrable that emits multiple items from this List, then flatMap
create an Observable
that makes the retrofit call for each UserSelfFollows.UserDataFollows
data object, (it will happens in parallel which seems more suits here, but you can also use concatMap
if you interested in sequential execution), then to collect all final data together, as a list of MediaData
objects, you can use the 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
}
});
Upvotes: 2
Reputation: 6117
Yosriz's answer put me in the right direction. So to avoid others pulling there hair out with this, here is the FULL code solution:
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));
}
}
});
Upvotes: 0
Reputation: 157437
I never used both flatMapIterable
or concatMap
, but as alternative solution you could use the flatMap
and compose
operator:
ServiceFactory.createRetrofitService().getUserFollowing(sessionMgr.getAuthToken())
.flatMap(list -> Observable.from(list))
.compose(getComposer())
.subscribe(mediaData -> mMediaDataList.add(mediaData), throwable -> {}, () -> { // on complete do something with mMediaList});
Where getComposer()
returns a Transformer UserSelfFollows
-> Media.MediaData
protected Observable.Transformer<UserSelfFollows, Media.MediaData> getComposer() {
return ;
}
Upvotes: 1