I am using RxJava in my android app along with Retrofit to make network requests to a server. I am using RxJavaCallAdapterFactory so I can have my retrofit requests return singles. In my code, the retrofit object is named 'api'.
The code here works fine, but in this example, I need to retrieve the userId before I can make a playlist. I flat map the userId request to the API request, and after making the playlist, I need to use flat map again to convert the JSON response to a usable object.
public JSONUser me;
public Single<String> getUserId(){
if(me != null){
return Single.just(me.getUserId());
}
return api.getMe().flatMap(new Func1<JSONUser, Single<String>>() {
@Override
public Single<String> call(JSONUser meResult) {
me = meResult;
return Single.just(me.getUserId());
}
});
}
public Single<Playlist> createPlaylist(String name) {
final NewPlaylistConfig config = new NewPlaylistConfig(name);
return getUserId().flatMap(new Func1<String, Single<Playlist>>() {
@Override
public Single<Playlist> call(String userId) {
return api.createPlaylist(userId, config).flatMap(
new Func1<JSONPlaylist, Single<? extends SpotifyPlaylist>>() {
@Override
public Single<? extends Playlist> call(JSONPlaylist data) {
return Single.just(new Playlist(data));
}
});
}
});
}
The entry point here would be createPlaylist(). NewPlaylistConfig will be converted to JSON and is simply the body parameter for the POST request. UserId is needed as a path parameter.
My main question here, is if there is a way to chain these operations without the "callback-hell" you see here. Like I said, this code works but it is really ugly. I would appreciate if somebody could point me in the right direction regarding this. Is there a way to make this work like promises where you can just chain .thens?
Thank you.
subscribeOn is executed during the subscription process and affects both upper, and lower streams. It also can change the thread as many times as you write it. The one closest to the top of the chain is applied. observeOn affects only the lower streams, and is executed during emission.
Map transforms the items emitted by an Observable by applying a function to each item. FlatMap transforms the items emitted by an Observable into Observables. So, the main difference between Map and FlatMap that FlatMap mapper returns an observable itself, so it is used to map over asynchronous operations.
Single. Single is an Observable that always emit only one value or throws an error. A typical use case of Single observable would be when we make a network call in Android and receive a response. Sample Implementation: The below code always emits a Single user object.
RxJava is a Java VM implementation of ReactiveX a library for composing asynchronous and event-based programs by using observable sequences. The building blocks of RxJava are Observables and Subscribers. Observable is used for emitting items and Subscriber is used for consuming those items.
Instead of:
getUserId()
.flatMap(new Func1<String, Single<Playlist>>() {
@Override
public Single<Playlist> call(String userId) {
return api.createPlaylist(userId, config).flatMap(
new Func1<JSONPlaylist, Single<? extends SpotifyPlaylist>>() {
@Override
public Single<? extends Playlist> call(JSONPlaylist data) {
return Single.just(new Playlist(data));
}
});
}
});
write:
getUserId()
.flatMap(new Func1<String, Single<Playlist>>() {
@Override
public Single<Playlist> call(String userId) {
return api.createPlaylist(userId, config);
}
})
.flatMap(
new Func1<JSONPlaylist, Single<? extends SpotifyPlaylist>>() {
@Override
public Single<? extends Playlist> call(JSONPlaylist data) {
return Single.just(new Playlist(data));
}
});
Actually you can chain flatmap (and map) like you chain then with promises.
Note you can replace the second flatmap with map, replacing:
return Single.just(new Playlist(data));
with:
return new Playlist(data);
Result :
getUserId()
.flatMap(new Func1<String, Single<Playlist>>() {
@Override
public Single<Playlist> call(String userId) {
return api.createPlaylist(userId, config);
}
})
.map(
new Func1<JSONPlaylist, SpotifyPlaylist>() {
@Override
public SpotifyPlaylist call(JSONPlaylist data) {
return new Playlist(data);
}
});
Edit: you can go further with java 8:
getUserId()
.flatMap(userId -> api.createPlaylist(userId, config))
.map(data -> new Playlist(data));
Or Kotlin:
getUserId()
.flatMap { api.createPlaylist(it, config) }
.map { Playlist(it) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With