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!
In service I post my event :
RxBus.getSubject().onNext(eventAddNoteAndRealize) ;
This is my RxBus :
public final class RxBus {
private static final BehaviorSubject<Object> behaviorSubject
= BehaviorSubject.create();
public synchronized static BehaviorSubject<Object> getSubject() {
return behaviorSubject;
}
}
And In my Activity I have this :
DisposableObserver<Object> disposable = RxBus.getSubject().
subscribeWith(new DisposableObserver<Object>() {
#Override
public void onNext(Object o) {
if (o instanceof EventAddNoteAndRealize) {
Toast.makeText(NewMainActivity.this , "next", Toast.LENGTH_LONG).show();
EventAddNoteAndRealize event = new EventAddNoteAndRealize(((EventAddNoteAndRealize) o).getNoteAndRealizeDAOList());
eventAddNoteAndRealize = event;
getRealizeAndNote((EventAddNoteAndRealize)o);
}
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
And a method onNext execute two times this same objects. I do not have idea what I did wrong
Are you sure that you are not emitting the same object 2 times because as i test your code it works good
#Override
public void run(String... args) throws Exception {
DisposableObserver<Object> disposable = RxBus.getSubject().
subscribeWith(new DisposableObserver<Object>() {
#Override
public void onNext(Object o) {
System.out.println(o);
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
Observable.interval(100, TimeUnit.MILLISECONDS)
.map(aLong -> {
RxBus.getSubject().onNext(aLong);
return aLong;
}).subscribe();
}
}
final class RxBus {
private static final BehaviorSubject<Object> behaviorSubject
= BehaviorSubject.create();
public synchronized static BehaviorSubject<Object> getSubject() {
return behaviorSubject;
}
make sure that you are not emitting object to times my response is
0
1
2
3
4
5
6
.
.
.
I have this code to wrap a callback in Rx Java 1 and it compiles fine , but now that I have switched to RX Java 2 it does not compile...what is the equivalent in Rx Java 2?
return Observable.fromEmitter(new Action1<AsyncEmitter<Integer>>() {
#Override
public void call(AsyncEmitter<Integer> emitter) {
transObs.setTransferListener(new TransferListener() {
#Override
public void onStateChanged(int id, TransferState state) {
if (state == TransferState.COMPLETED)
emitter.onCompleted();
}
#Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
}
#Override
public void onError(int id, Exception ex) {
emitter.onError(ex);
}
});
emitter.setCancellation(new AsyncEmitter.Cancellable() {
#Override
public void cancel() throws Exception {
transObs.cleanTransferListener();
}
});
}
}, AsyncEmitter.BackpressureMode.BUFFER);
UPDATE:
I came up with this, but Do you have to deal with backpressure since its an oncreate call?
return Observable.create(new ObservableOnSubscribe<List<DigitsUser>>() {
#Override
public void subscribe(final ObservableEmitter<List<DigitsUser>> emitter) throws Exception {
mDigitFriends.findFriends((gotEm, users) -> {
emitter.onNext(users);
});
emitter.setCancellable(() -> {
emitter.onNext(null);
});
}
});
If you're worried about backpressure you should use the Flowable class. Here's a quote from the RxJava2 Wiki:
Practically, the 1.x fromEmitter (formerly fromAsync) has been renamed
to Flowable.create.
Here is your example using the Flowable class:
return Flowable.create(new FlowableEmitter<List<DigitsUser>>() {
#Override
public void subscribe(final FlowableEmitter<List<DigitsUser>> emitter) throws Exception {
mDigitFriends.findFriends((gotEm, users) -> {
emitter.onNext(users);
});
emitter.setCancellable(() -> {
emitter.onNext(null);
});
}
}, BackpressureStrategy.BUFFER);
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 :)
Is it possible to resubscribe an Observable and get the error?
The Observable<T> retry() method resubscribes the observable but it consumes the error.
final PublishSubject<Integer> observable = PublishSubject.create();
observable
.flatMap(new Func1<Integer, Observable<Integer>>() {
#Override
public Observable<Integer> call(final Integer integer) {
if (integer % 2 == 0) {
return Observable.just(integer);
} else {
return Observable.error(new Exception("int: " + integer));
}
}
})
.retry()
.subscribe(new Action1<Integer>() {
#Override
public void call(final Integer integer) {
Timber.i("integer: %d", integer);
}
},
new Action1<Throwable>() {
#Override
public void call(final Throwable throwable) {
Timber.e(throwable, "throwable");
}
},
new Action0() {
#Override
public void call() {
Timber.w("onCompleted");
}
});
Observable
.range(0, 10)
.delay(2, TimeUnit.MILLISECONDS)
.subscribe(new Action1<Integer>() {
#Override
public void call(final Integer integer) {
observable.onNext(integer);
}
},
new Action1<Throwable>() {
#Override
public void call(final Throwable throwable) {
observable.onError(throwable);
}
},
new Action0() {
#Override
public void call() {
observable.onCompleted();
}
});
The onError part of observable is never called because .retry() consumes the error.
What you're looking for is retryWhen(). This allows you to pass a Func1 which provides you with the Throwable, that means you can place your onError logic there instead.
This is a good article.