RxJava flat map: what happens when one of the resulting observable complete? - java

I'm new to RxJava, I know flatmaps are for mapping an emitted item to observable. I also know that based on the documentation the emitted observables all get combined (flatten) to a single observable stream.
I was wondering what happens if any of those inner observables get completed?
for example: I have an observable that emits a item data key. I have to make another async http call to get the item data from the server, so I call it by using another observable. I use a flat map to connect these two and create one main observable.
When does the run() method of following "SomeMethodThatWantsItems" get called?
public void someMethodThatWantsItems(MyHttpCaller httpCaller, SomeSearchEngine searchEngine)
{
Consumer<Item> onNextConsumer =
Observable<Item> searchObservable = getSearchResult(httpCaller, searchEngine, "The Search Word");
searchObservable
.subscribeOn(Schedulers.newThread())
.subscribe(new Consumer<Item>(){
#Override
public void accept(#NonNull Item item) throws Exception {
//Do stuff with the item
}
}
, new Consumer<Exception>() { //some implementation of onErrorConsumer
}
//OnComplete
, new Action(){
#Override
public void run() throws Exception {
//When does this get called??? after the search complete or when the first http call is successful?
}
});
}
private Observable<String> getSearchResultKeys(SomeSearchEngine searchEngine, String someSearchWord)
{
return Observable.create(new ObservableOnSubscribe<String>() {
#Override
public void subscribe(#NonNull final ObservableEmitter<String> emitter) throws Exception {
//Assume that our search engine call onFind everytime it finds something
searchEngine.addSearchListener(new searchEngineResultListener(){
#Override
public void onFind(String foundItemKey){
emitter.onNext(foundItemKey);
}
#Override
public void onFinishedFindingResults(){
emitter.onComplete();
}
});
}
});
}
private Observable<Item> getItemByKey(MyHttpCaller httpCaller, String key)
{
return Observable.create(new ObservableOnSubscribe<Item>() {
#Override
public void subscribe(#NonNull final ObservableEmitter<Item> emitter) throws Exception {
//Call the server to get the item
httpCaller.call(key, new onCompleteListener(){
#Override
public void onCompletedCall(Item result)
{
emitter.onNext(result);
//The result is complete! end the stream
emitter.onComplete();
}
});
}
});
}
public Observable<Item> getSearchResult(MyHttpCaller httpCaller, SomeSearchEngine searchEngine, String someSearchWord){
//Where everything comes together
Observable<String> searchResultObservable = getSearchResultKeys(searchEngine, someSearchWord);
retuern searchResultObservable
.observeOn(Schedulers.newThread())
.flatMap(new Function<String, Observable<Item>>(){
#Override
public Observable<Item> apply(String key){
return getItemByKey(httpCaller, key);
}
});
}

The onComplete() always get call once and then the streams stops. (this is part of the Observable Contract).
That means that in your case, your onComplete() at SomeMethodThatWantsItems will be called after all items were retrieved.
In case of flatMap(), completion of each inner Observable, simply will signal the source Observable to stop flatting item from the inner Observable to the source Observable, flatMap() merges items from the inner Observable as long as this stream sends items, so it's basically consume the entire inner Observable stream into the source stream, the entire stream is until termination event3 like onComplete(), so in case where inner Observable can emit more than 1 item, that means that it will make more than 1 emission on the source stream.

Related

How I would use SwitchMap (RXJAVA) in my code?

I'm new to Android development and am currently trying to make a simple MVC app that works with Rest API.
API calls are made without using Retrofit, although this is not so important. The main catch is that using Observable with debounce and SwitchMap I still get too many API calls (and the extra ones should be discarded). The function is called when text is entered (EditText Listener with TextWatcher). And when administered continuously without delay word, every symbol processed by the server and should only be administered when not within 600 milliseconds. Please help me.
public Observable<String> getObservable(final String s){
return Observable
.create(new ObservableOnSubscribe<String>() {
#Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext(model.translateText(s));
}
});
}
public Observer<String> observer = new Observer<String>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String s) {
mainView.hideProgress();
mainView.showResult(s);
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
};
public void onEditTextChange(String textForTranslate){
mainView.showProgress();
getObservable(textForTranslate)
.debounce(600,TimeUnit.MILLISECONDS)
.switchMap(new Function<String, ObservableSource<String>>() {
#Override
public ObservableSource<String> apply(String s) throws Exception {
return Observable.just(s);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
}
You are creating a new observable every time a character is typed. So multiple observers are created with each having separate debounce (time throttle) and switch but they are not reused. Instead you create a new observable whenever text changes and start rx chain on it.
You need to create a single PublishSubject
private final PublishSubject<String> querySubject = PublishSubject.create();
that emits entered text/query whenever text is changed. Use it in your callback:
public void onEditTextChange(String textForTranslate) {
querySubject.onNext(textForTranslate);
}
And in your main function, subscribe to observable:
querySubject
.debounce(600, TimeUnit.MILLISECONDS)
.distinctUntilChanged()
.switchMap(new Function<String, ObservableSource<String>>() {
#Override
public ObservableSource<String> apply(String s) throws Exception {
// perform api call or any other operation here
return Observable.just(s);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
Debounce operator emits single item only after given time (600 ms) has passed. It ignores items if current item is being processed and given time has not passed.
distinctUntilChanged helps in reducing processing of same query.

RxJava sewing two queries

How to sew two Observable in RxJava ?
Observable<List<CalendarEvent>>, for each CalendarEvent, I want to do network operation to read the (lat,lon) and fetch place name, and then combine place name back to CalendarEvent.
public Observable<List<CalendarEvent>> getEvents() {
// get events
// translate each Event LatLng to Place and bind it to Event
// return the events
}
public Observable<List<CalendarEvent>> getEvents() {
List<CalendarEvent> sourceList = ...
return Observable.from(sourceList) //emits each item separately
.concatMap(calendarEvent -> applyPlaceName(calendarEvent)) //fetches places and applies them for each item
//fyi: concatMap executes requests sequentially, if you want do it in parallel - use flatMap instead
.toList(); //collects items to list
}
//somewhere in your Networking class
public Observable<CalendarEvent> applyPlaceName(CalendarEvent calendarEvent) {
return Observable ... //do network call and apply placeName on item
}
//p.s. don't forget to apply appropriate Schedulers
No need for something fancy here, this would roughly do what you want I think:
public class Foobar {
void doSomethingWithEvents() {
getEvents().subscribe(new Action1<List<CalendarEvent>>() {
#Override
public void call(List<CalendarEvent> calendarEvents) {
for (CalendarEvent event : calendarEvents) {
getPlaceForEvent(event).subscribe(new Action1<Place>() {
#Override
public void call(Place place) {
event.setPlace(place);
}
});
}
}
});
}
Observable<Place> getPlaceForEvent(CalendarEvent event) {
return Observable.just(new Place());
}
Observable<List<CalendarEvent>> getEvents() {
return Observable.just(new ArrayList<CalendarEvent>());
}
}

How do I change rx.Observable<java.util.list<T>> to java.util.list<T>

Declaration
#GET("api/Game/SearchGames")
Observable<List<GameModel>> searchGames();
This is the network call
public static Observable<List<GameModel>> searchGames () {
VersusAPI client = VersusServiceGenerator.createService(VersusAPI.class);
Observable<List<GameModel>> ob = client.searchGames();
return ob;
}
Here is where I implement.
mAdapterMyGames = new RecyclerViewAdapter(searchGames());
searchGames() returns rx.Observable<java.util.list<GameModel>>. How do I change that to only java.util.list<GameModel>?
You don't properly understand what is an Observable.
It is an object, to which You can subscribe() to get the result of it's operation. Usually, only when subscribing to an Observable it starts and you can get the result inside Subscriber's onNext() function.
So in your case:
Subscribe to this Observable.
Look for the result inside this subscriber's onNext function.
searchGames().subscribe(new new Subscriber<List<GameModel>>() {
#Override
public void onNext(List<GameModel> gameModels) {
//TODO make sth useful with models
}
#Override
public void onCompleted() { }
#Override
public void onError(Throwable e) { }
)

RxJava and list of `Single` observable

I'm new in RxJava so I still have many doubts.
I'm creating this:
#Override
public Single<Result> saveUser(final User user) {
return Single.create(new Single.OnSubscribe<Result>() {
#Override
public void call(final SingleSubscriber<? super Result> singleSubscriber) {
if(user.isValid()){
save(user);
//Set result ok
singleSubscriber.onSuccess(result);
} else {
//This sets an error.
singleSubscriber.onError(error);
}
}
});
}
Depending of the success of the operation, the Single emits it's data and who is subscribed receives the data.
The problem now is that at some point I need to store a list of users. Something like:
public void saveUsers(List<User> listOfUsers){
for (User user : listOfUsers) {
saveUser(user);
}
}
How can I create an Single so I can be subscribed to the initial Single
I would rather create flatmap out of observable list.
public void saveUsers(List<User> listOfUsers){
Observable.from(listOfUsers).flatMap((User user)->{
if(user.isValid()){
save(user);
//Set result ok
return Observable.just(result);
}else
return Observable.error(new RuntimeException("..."));
}).retry(2);
}
If you make your saveUsers method blocking, call Observable#toBlocking.

Returning an ArrayList of an object in rxAndroid

I want to run a method periodically such that it returns an ArrayList of a custom object. Here is my code snippet,
subscribe = Observable.interval(5, TimeUnit.SECONDS)
.map(new Func1<Long, ArrayList<Item>>() {
#Override
public ArrayList<Item> call(Long aLong) {
return new ArrayList<Item>(aLong.intValue());
}
});
However, this gives an error
map(rx.functions.Func1<? super T, ? extends R>)in Observable cannot be applied to (anonymous rx.functions.Func1<java.lang.Long, java.util.ArrayList<com.example.Item>>)
This works fine when the returned value is an ArrayList<String>. I do not understand what the problem is here. Are custom objects not allowed?
You don't get subscription on map, you get it after subscribing. Here's sample code for demonstrating it.
Observable<ArrayList<Item>> observable = Observable.interval(5, TimeUnit.SECONDS)
.map(new Func1<Long, ArrayList<Item>>() {
#Override
public ArrayList<Item> call(Long aLong) {
return new ArrayList<Item>(aLong.intValue());
}
});
Subscription subscription = observable.subscribe(new Action1<ArrayList<Item>>() {
#Override
public void call(ArrayList<Item> items) {
//Do something with list items here
}
});

Categories

Resources