this is a method written in RxJava
public Observable<String> method() {
return model.getOffers()
.filter(new Func1<Offers, Boolean>() {
#Override
public Boolean call(Offers offers) {
if (offers == null)
return false;
return offers.hasSuperOffer();
}
})
.flatMap(new Func1<Offers, Observable<Long>>() {
#Override
public Observable<Long> call(Offers offers) {
Long offerEndTime = offers.getRemainingTime();
if (offerEndTime == null) {
return Observable.empty();
}
AtomicLong remainingTimeSec;
Long currentTimeSec = System.currentTimeMillis() / 1000;
if (remainingTimeSec.get() == -1 && (offerEndTime > currentTimeSec)) {
remainingTimeSec.set(offerEndTime - currentTimeSec);
} else {
return Observable.empty();
}
return Observable.interval(1, TimeUnit.SECONDS)
.onBackpressureDrop()
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.take(remainingTimeSec.intValue())
.doOnUnsubscribe(new Action0() {
#Override
public void call() {
}
})
.doOnCompleted(new Action0() {
#Override
public void call() {
}
})
.map(new Func1<Long, Long>() {
#Override
public Long call(Long elapsedTimeSec) {
return remainingTimeSec.getAndDecrement();
}
});
}
})
.map(new Func1<Long, String>() {
#Override
public String call(Long remainingTime) {
return DateUtils.getRemainingTimeStr(remainingTime);
}
});
}
I am trying to convert it to RxJava3 but some parameters have changed:
Func1 has been changed to Function
Action0 has been changed to Action
After I'm making the changes the following error appears at filter:
filter (io.reactivex.rxjava3.functions#io.reactivex.rxjava3.annotations.NonNull Predicate <? MyClass> in Observable cannot be applied to (anonymous.io.reactivex.rxjava3.functions.Function <MyClass.model.Offers.java.lang.Boolean>)
Can anyone help me?
Thank you!
If I'm using retrofit with a rxjava converter to get the response, how and where can I filter the results (into say a List<> of users for example whos property boolean paidDues = true)?
Observable<User> observable = userService.me();
observable.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<User>() {
#Override
public void onCompleted() { // handle completed }
#Override
public void onError(Throwable e) { // handle error }
#Override
public void onNext(User user) { // handle response }
});
Use a Filter:
Observable<User> observable = userService.me();
observable.observeOn(AndroidSchedulers.mainThread())
.filter(new Predicate<User >() {
#Override
public boolean test(#NonNull final User user) throws Exception {
return user.hasPaidDues(); // or something like this
}
})
.subscribe(...);
I have an Observable<MoviesResponse>. My MovieResponse class contains a getResults() methods returning a List<Result>. This Result class has a getTitle() methods returning a String. I want to call the getTitle() methods of all my Result objects to get all the titles of my movies.
I achieved this with the code below using a foreach loop but I think there is a better way to do this by chaining RxJava operators, I just can't figure it out...
Subscription :
Observable<MoviesResponse> moviesResponseObservable = apiService.getTopRatedMoviesObservable(API_KEY);
subscription = moviesResponseObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<MoviesResponse>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(MoviesResponse moviesResponse) {
List<Result> results = moviesResponse.getResults();
for (Result r:results) {
Log.d(LOG_TAG,r.getTitle());
}
}
});
Interface :
public interface ApiService {
#GET("movie/top_rated")
Observable<MoviesResponse> getTopRatedMoviesObservable(#Query("api_key") String apiKey);
}
You can use a flatmap to transform your observable into an Observable<Result> and then use map to turn that into Observable<String>, which you can then subscribe to.
moviesReponseObservable
.subscribeOn(Schedulers.io())
.flatMapIterable(new Function<MoviesResponse, Iterable<Result>>() {
#Override
public Iterable<Result> apply(#NonNull MoviesResponse moviesResponse) throws Exception {
return moviesResponse.getResults();
}
})
.map(new Function<Result, String>() {
#Override
public String apply(#NonNull Result result) throws Exception {
return result.getTitle();
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
#Override
public void onNext(String s) {
Log.d("TAG", s);
}
/* ... */
});
I got the following error with #zsmb13 answer :
new Function : map (rx.functions.Func1) in
Observable cannot be applied to (anonymous
java.util.function.Function)reason:
no instance(s) of type variable(s) R exist so that Function conforms to Func1
Anyway this answer was very helpul I just replaced Function with Func1 and used call method.
subscription = moviesResponseObservable
.subscribeOn(Schedulers.io())
.flatMapIterable(new Func1<MoviesResponse, Iterable<Result>>() {
#Override
public Iterable<Result> call(MoviesResponse moviesResponse) {
return moviesResponse.getResults();
}
})
.map(new Func1<Result, String>() {
#Override
public String call(Result result) {
return result.getTitle();
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
Log.d(LOG_TAG, s);
}
});
I've been trying to learn RxJava2 and I've been struggling with this one..
So, I have a structure that represents an events that goes something like the following:
class Event{
public Date when;
public String eventName;
}
And somewhere I query a list of events from the repository that I want to group by date.
So, given a list of events like:
Event1 at June
Event2 at June
Event3 at July
Event4 at August
Event5 at August
I want to group them so that
June
Event1
Event2
July
Event3
August
Event4
Event5
What I have so far is, in my opinion, very ugly and I am pretty sure I am over-"engineering" this...
repository.getAllEvents()
.toObservable()
.flatMap(new Function<Events, Observable<Event>>() {
#Override
public Observable<Event> apply(#NonNull Events events) throws Exception {
return Observable.fromIterable(events.getEvents());
}
})
.groupBy(new Function<Event, Date>() {
#Override
public Date apply(#NonNull Event event) throws Exception {
return event.when;
}
})
.flatMap(new Function<GroupedObservable<Date, Event>, Observable<Object>>() {
#Override
public Observable<Object> apply(#NonNull GroupedObservable<Date, Event> dateEventGroupedObservable) throws Exception {
final Date key = dateEventGroupedObservable.getKey();
return dateEventGroupedObservable.toList().toObservable().flatMap(new Function<List<Event>, ObservableSource<?>>() {
#Override
public ObservableSource<?> apply(#NonNull List<Event> events) throws Exception {
return Observable.just(new Pair<Date, List<Event>>(key, events));
}
});
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new Observer<Object>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Object o) {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
So far, this gives me an observable that delivers a Pair> but as you can see it gets converted to Object and I honestly can't make sense out of the generics hell -.-'
Any tips on how I could approach this?
Thanks
You can achieve this simply by using collect operator:
repository.getAllEvents()
.flatMapIterable(events -> events.getEvents())
.collect(() -> new HashMap<Date, List<Event>>(),
(map, event) -> putEventIntoMap(map, event)
)
...
Without lambdas:
// I assume that getAllEvents returns Events class
repository.getAllEvents()
.flatMapIterable(new Function<Events, Iterable<? extends Event>>() {
#Override
public Iterable<? extends Event> apply(#NonNull Events events) throws Exception {
return events.getEvents();
}
})
.collect(new Callable<HashMap<Date, List<Event>>>() {
#Override
public HashMap<Date, List<Event>> call() throws Exception {
return new HashMap<Date, List<Event>>();
}}, new BiConsumer<HashMap<Date, List<Event>>, Event>() {
#Override
public void accept(#NonNull HashMap<Date, List<Event>> map, #NonNull Event event) throws Exception {
putEventIntoMap(map, event);
}}
)
...
Method to put event into map:
private void putEventIntoMap(HashMap<Date, List<Event>> map, Event event) {
if (map.containsKey(event.when)) {
map.get(event.when).add(event);
} else {
List<Event> list = new ArrayList<>();
list.add(event);
map.put(event.when, list);
}
}
Based on #Maxim Ostrovidov answer I was able to adapt it into the following working solution:
repository.getAllEvents()
// Convert the Single<Events> into an Observable<Events>
.toObservable()
// Transform the stream Events into a List<Event> stream / observable
.flatMapIterable(new Function<Events, List<Event>>() {
#Override
public List<Event> apply(#NonNull Events events) throws Exception {
return events.getEvents();
}
})
// Group each Event from the List<Event> by when (date)
.groupBy(new Function<Event, Date>() {
#Override
public Date apply(#NonNull Event event) throws Exception {
return event.when;
}
})
// For each grouped stream (not sure if its correct to call it like this)
// Lets generate a new stream that is a Pair<Date, List<Event>>
.flatMap(new Function<GroupedObservable<Date, Event>, Observable<Pair<Date, List<Event>>>>() {
#Override
public Observable<Pair<Date, List<Event>>> apply(#NonNull GroupedObservable<Date, Event> dateEventGroupedObservable) throws Exception {
final Date key = dateEventGroupedObservable.getKey();
// toList() takes a big role here since it is forcing
// for the dateEventGroupedObservable to complete and only then
// streaming a Single<List<Event>> which is why I convert it back to observable
return dateEventGroupedObservable.toList().toObservable().flatMap(new Function<List<Event>, Observable<Pair<Date, List<Event>>>>() {
#Override
public Observable<Pair<Date, List<Event>>> apply(#NonNull List<Event> events) throws Exception {
return Observable.just(new Pair<Date, List<Event>>(key, events));
}
});
}
})
// We can now collect all streamed pairs of (Date, List<Event>)
// into an HashMap
.collect(new Callable<HashMap<Date, List<Event>>>() {
#Override
public HashMap<Date, List<Event>> call() throws Exception {
return new HashMap<Date, List<Event>>();
}
}, new BiConsumer<HashMap<Date, List<Event>>, Pair<Date, List<Event>>>() {
#Override
public void accept(#NonNull HashMap<Date, List<Event>> dateListHashMap, #NonNull Pair<Date, List<Event>> dateListPair) throws Exception {
dateListHashMap.put(dateListPair.first, new ArrayList<Event>(dateListPair.second));
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new SingleObserver<HashMap<Date, List<Event>>>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onSuccess(HashMap<Date, List<Event>> dateListHashMap) {
}
#Override
public void onError(Throwable e) {
}
});
Yes, it is long and it is ugly but I am pretty sure that with lambdas this would look better. Now, the thing is... This code is used to feed a recycler view adapter so I wonder if it wouldn't be easier to simple do this in an imperative way... oh well, serves the study purpose :)
How can I add an observable to an Integer object, such that I get notified of every object update? In this case Integer number = 0; and I would like to get notified every time I add for example 1. Initially I just want to log the event. This is what I have so far, but I'm stuck.
code:
Subscriber<Integer> num = new Subscriber<Integer>() {
#Override
public void onNext(Integer num) { Log.d("RX", num.toString()); }
#Override
public void onError(Throwable e) { Log.d("RX", "error"); }
#Override
public void onCompleted() { Log.d("RX", "completed"); }
};
Observable.just(number)
/*.doOnNext(new Action1<Integer>() {
#Override
public void call(Integer integer) {
Log.d("RX", "Updated integer" + integer.toString());
}
})*/
/*.flatMap(new Func1<Integer, Observable<?>>() {
#Override
public Observable<?> call(Integer integer) {
Log.d("RX", "Updated integer" + integer.toString());
return Observable.just(number);
}
})*/
.subscribe(num);
Without knowing exactly what you are trying to achieve it's hard to give the best answer but you could implement an ObservableInteger class along the lines of the following:
public class ObservableInteger {
private Integer value;
private PublishSubject<Integer> subject = PublishSubject.create();
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
subject.onNext(value);
}
public Observable<Integer> getObservable() {
return subject.asObservable();
}
}
Then you are able to subscribe to it:
ObservableInteger obInt = new ObservableInteger();
Subscription s = obInt
.getObservable()
.subscribe(
integer -> {
// each time a new value is set
// it will be emitted here
},
Throwable::printStackTrace
);
I came across this post today and realized it is written for RxJava1. There are several changes in RxJava 2. Some of them affecting the above sample. (.subscribe returns a Disposable https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#subscription and .asObservable() is now .hide() in RxJava 2.0 https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#instance-methods)
Here is the RxJava2 compatible solution of Jahnolds answer:
public class ObservableInteger {
private Integer value;
private PublishSubject<Integer> subject = PublishSubject.create();
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
subject.onNext(value);
}
public Observable<Integer> getObservable() {
return subject.hide();
}
}
and subscribe like so:
ObservableInteger obInt = new ObservableInteger();
Disposable d = obInt
.getObservable()
.subscribe(
integer -> {
// each time a new value is set
// it will be emitted here
},
Throwable::printStackTrace
);