Can we detect if a class member value is getting changed using RxJava?? Say in a class there is a variable var, now can we get notified whenever the value of var changes using RxJava.
You can use something like this:
private final BehaviorSubject<Integer> subject = BehaviorSubject.create();
private Integer value=0;
public Observable<Integer> getUiElementAsObservable() {
return subject;
}
public void updateUiElementValue(final Integer valueAdded) {
synchronized (value) {
if (valueAdded == 0)
return;
value += valueAdded;
subject.onNext(value);
}
}
and subscribe to it like this:
compositeSubscription.add(yourClass.getUiElementAsObservable()
.subscribe(new Action1<Integer>() {
#Override
public void call(Integer userMessage) {
setViews(userMessage,true);
}
}));
you have to create setter for all of your variables that you want something subscribe to their changes and call onNext if change applied.
UPDATE
When an observer subscribes to a BehaviorSubject, it begins by emitting the item most recently emitted by the source Observable
you can see other type of subjects here: http://reactivex.io/documentation/subject.html
some useful link:
about reactive programming : https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
and about rxjava : https://youtu.be/k3D0cWyNno4
http://rxmarbles.com/#distinctUntilChanged
Code
Observable.just("A", "B", "B", "A", "C", "A", "A", "D")
.distinctUntilChanged()
.subscribe(abc -> Log.d("RXJAVA", abc));
Result
A
B
A
C
A
D
Related
I need to chain two observables, the second depends on the first.
So what I have is:
Observable 1 -> petition returns Observable<TvShow>
//kotlin
fun getTvShow(): Observable<TvShow> {
return retrofitPetitionGetShow()...
}
//java
Observable<TvShow> getTvShow(){
return retrofitPetitionGetShow()...
}
Observable 2 -> returns Single<List<Season>>
Observable.range(1, TvShow.totalSeasons)
.flatMap { seasonNumber: Int ->
retrofitPetitionGetSeason(seasonNumber)....
}.toList()
What I need is the result of the second observable (List<Season>) to be added to the TvShow object TvShow.setList(List<Season>) and then return it.
Thank you in advance
Basing on provided information in comments you can try with the following code (it is Java code but it should be easy to convert that to Kotlin):
private Observable<TvShow> getTvShow() {
return retrofitPetitionGetShow();
}
private Single<List<Season>> getSeasons(TvShow tvShow) {
return Observable.range(1, tvShow.getTotalSeasons())
.flatMap(seasonNumber -> retrofitPetitionGetSeason(seasonNumber))
.toList();
}
public Observable<TvShow> chainObservables() {
return getTvShow()
.flatMap(tvShow -> getSeasons(tvShow).map(tvShow::withSeasons).toObservable());
}
IMPORTANT!
In reactive/functional way you should not modify objects, but create the new one (in your case, there is an update of tvShow with seasons list). There is a tvShow::withSeasons method reference which is implemented in this way:
public TvShow withSeasons(List<Season> seasons) {
return this.seasons == seasons ? this : new TvShow(this.name, this.totalSeasons, seasons);
}
I'm very new to RxJava. I have a problem with converting a nested async operation into RxJava structure. Having a single async task that fetches data from the server has not been a problem to create, however I do have a problem with an exemplary case of this sort:
List<A> aaa = new ArrayList<>();
List<B> bbb = new ArrayList<>();
new FetchItemA(String id){
#Override
protected void onPostExecute(List<A> items){
foreach(A item:items){
new FetchItemB(item.getId())
#Override
protected void onPostExecute(List<B> newItems){
neededList.addAll(newItems);
}
}
}
}
}
The problem is with the return types. I've created my observable this way:
Observable.fromArray(String userId)
.map(new Function(String, List<A>){
#Override
public List<A> apply(String id){
return getListA();
}
})
.map(new Function<String, List<B>){
#Override
public List<B> apply(String id){
someList.add(getItemB(id));
return someList;
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer(){
#Override
public void onCompleted(List<B> items){
bbb.addAll(items);
adapter.setItems(bbb);
}
});
This however is illegal as this Observableexpects the type List<A>whereas I'm returning List<B>. How can I structure my RxJava observable to be able to fetch a list of items (of type A, each having a unique id), and based on the fetched list, fetch a single item (of type B) with id (of each item of type A in the first list) as the argument, and only after add the received items (of type B) to a list?
The essential step in fetching the data is to transform each A into a B using a network call. In the RxJava world, that means wrapping the network call in an observable and then using the flatMap() operator.
Observable.fromList(aaa)
.flatMap(new Func1<A, Observable<B>>() {
#Override
public Observable<B> call(A a) {
return Observable.fromCallable(getNetworkValueAsB(item));
}
} )
.toList()
.subscribe( new Observer<List<B>>() {
#Override
public void onNext(B bItemList) {
bbb.addAll(bItemList);
adapter.setItems(bbb);
}
});
The operations are fromList() which converts from the List<A> to Observable<A>, flatMap() which converts from A to B using the call, and toList() which gathers all the B values produced into a list, which is then used in the subscription.
The fromList() operator might be called fromIterable() or from() depending on the version of the library you are using.
Edited to removed lambdas
I'm using RxJava, and I need to do 2 things:
Get the last element emitted from the Observable
Determine if onError was called, vs. onCompleted
I've looked at using last and lastOrDefault (which is actually the behavior I need), but I've not been able to work around onError hiding the last element. I would be OK with the Observable being used twice, once to get the last value and once to get the completion status, but so far I've only been able to accomplish this by creating my own Observer:
public class CacheLastObserver<T> implements Observer<T> {
private final AtomicReference<T> lastMessageReceived = new AtomicReference<>();
private final AtomicReference<Throwable> error = new AtomicReference<>();
#Override
public void onCompleted() {
// Do nothing
}
#Override
public void onError(Throwable e) {
error.set(e);
}
#Override
public void onNext(T message) {
lastMessageReceived.set(message);
}
public Optional<T> getLastMessageReceived() {
return Optional.ofNullable(lastMessageReceived.get());
}
public Optional<Throwable> getError() {
return Optional.ofNullable(error.get());
}
}
I've no problem with making my own Observer, but it feels like Rx should be better able to meet this use-case of "get the last element emitted before completion`". Any ideas on how to accomplish this?
Try this:
source.materialize().buffer(2).last()
In the error case the last emission will be a list of two items being the last value emitted wrapped as a Notification and the error notification. Without the error the second item will be the completion notification.
Note also that if no value is emitted then the result will be a list of one item being the terminal notification.
I solved with:
source.materialize().withPrevious().last()
where withPrevious is (Kotlin):
fun <T> Observable<T>.withPrevious(): Observable<Pair<T?, T>> =
this.scan(Pair<T?, T?>(null, null)) { previous, current -> Pair(previous.second, current) }
.skip(1)
.map { it as Pair<T?, T> }
Have you try onErrorResumeNext here you can see the rest or error handling operators https://github.com/ReactiveX/RxJava/wiki/Error-Handling-Operators
I used this approach to solve your problem.
public class ExampleUnitTest {
#Test
public void testSample() throws Exception {
Observable.just(1, 2, 3, 4, 5)
.map(number -> {
if (number == 4)
throw new NullPointerException();
else
return number;
})
.onErrorResumeNext(t -> Observable.empty())
.lastOrDefault(15)
.subscribe(lastEmittedNumber -> System.out.println("onNext: " + lastEmittedNumber));
}
}
It will emit onNext: 3
Hope that it helps.
I have three Observables which I combine with combineLastest:
Observable<String> o1 = Observable.just("1");
Observable<String> o2 = Observable.just("2");
Observable<String> o3 = Observable.just("3");
Observable.combineLatest(o1, o2, o3, new Func3<String, String, String, Object>() {
#Override
public Object call(String s, String s2, String s3) {
return null;
}
});
I want to be notified about the first emission of one of the Observables without ignoring the later emissions, which I guess first operator would do. Is there a convenient operator for that like (example):
o1.doOnFirst(new Func1<String, Void>() {
#Override
public Void call(String s) {
return null;
}
})
I think you can have a practical doOnFirst with a simple take if you're handling a stream:
public static <T> Observable<T> withDoOnFirst(Observable<T> source, Action1<T> action) {
return source.take(1).doOnNext(action).concatWith(source);
}
This way the action is only bound to the first item.
This could be changed to handle observables which are not backed by streams adding skip to skip the already taken items:
public static <T> Observable<T> withDoOnFirstNonStream(Observable<T> source, Action1<T> action) {
return source.take(1).doOnNext(action).concatWith(source.skip(1));
}
For convenience, I created these extension functions for Flowable and Observable.
Note, that with doOnFirst() the action will be called before the first element emission, whilst doAfterFirst() will firstly emit the first item and then perform the action.
fun <T> Observable<T>.doOnFirst(onFirstAction: (T) -> Unit): Observable<T> =
take(1)
.doOnNext { onFirstAction.invoke(it) }
.concatWith(skip(1))
fun <T> Flowable<T>.doOnFirst(onFirstAction: (T) -> Unit): Flowable<T> =
take(1)
.doOnNext { onFirstAction.invoke(it) }
.concatWith(skip(1))
fun <T> Observable<T>.doAfterFirst(afterFirstAction: (T) -> Unit): Observable<T> =
take(1)
.doAfterNext { afterFirstAction.invoke(it) }
.concatWith(skip(1))
fun <T> Flowable<T>.doAfterFirst(afterFirstAction: (T) -> Unit): Flowable<T> =
take(1)
.doAfterNext { afterFirstAction.invoke(it) }
.concatWith(skip(1))
Usage is as simple as this:
Flowable.fromArray(1, 2, 3)
.doOnFirst { System.err.println("First $it") }
.subscribe { println(it) }
Output:
// First 1
// 1
// 2
// 3
And:
Flowable.fromArray(1, 2, 3)
.doAfterFirst { System.err.println("First $it") }
.subscribe { println(it) }
Output:
// 1
// First 1
// 2
// 3
There are a couple of solutions I can think of.
The first one is an ugly but simple hack of doOnNext. Just add a boolean field to the Action1 indicating whether the first item has been received. Once received, do whatever it is you want to do, and flip the boolean. For example:
Observable.just("1").doOnNext(new Action1<String>() {
boolean first = true;
#Override
public void call(String t) {
if (first) {
// Do soemthing
first = false;
}
}
});
The second one is to subscribe twice on the observable you want to monitor using publish or share(), with one of those publications going through first (depending on whether you want to manually connect to the published observable). You'll end up with two separate observables that emit the same items, only the first one will stop after the first emission:
ConnectableObservable<String> o1 = Observable.just("1").publish();
o1.first().subscribe(System.out::println); //Subscirbed only to the first item
o1.subscribe(System.out::println); //Subscirbed to all items
o1.connect(); //Connect both subscribers
Using rxjava-extras:
observable
.compose(Transformers.doOnFirst(System.out::println))
It's unit tested and under the covers just uses a per-subscription counter in an operator. Note that per-subscription is important as there are plenty of uses cases where an observable instance gets used more than once and we want the doOnFirst operator to apply each time.
Source code is here.
I need to observe a list of objects and emit an event as soon as there is a new object in the list. Like a client - server application where the client adds content to the list and the server emits the newly added content to all the clients registered in the server.
So far, my observable only emits one item and nothing more after it. In other words, when a new object is added in to the list there is an event but when a second (or 3rd, 4th, 5th...) object is added there is no event.
I need it to keep emiting items as soon as there are new objects in the list.
This is my code, where MyList is let's say my own implementation of List (not relevant to my question). I want the emitted event to be the newly added object to MyList.
private void onClickMethod() {
MyList myList = populateMyList();
onNexAction = new Action1<MyList>() {
#Override
public void call(MyList myList) {
System.out.println("call()");
TheObject theObject = myList.getNext();
System.out.println("New Event: " + theObject.getData());
}
};
myObservable = Observable.create(new Observable.OnSubscribe<MyList>() {
#Override
public void call(Subscriber<? super MyList> t) {
t.onNext(myList);
}
});
myObservable.observeOn(Schedulers.newThread()).subscribeOn(Schedulers.io()).subscribe(onNexAction);
}
The code above will only emit the first added object. But if I place a while cycle inside call() it will be emitting all the events, like I want. But I feel like not the appropriate way to do what I want. I feel like I'm more like polling rather than async.
Here is the exact same code but with the while cycle:
private void onClickMethod() {
MyList myList = populateMyList();
onNexAction = new Action1<MyList>() {
#Override
public void call(MyList myList) {
System.out.println("call()");
while (myList.size() > 0) { // The while cycle
TheObject theObject = myList.getNext();
System.out.println("New Event: " + theObject.getData());
}
}
};
myObservable = Observable.create(new Observable.OnSubscribe<MyList>() {
#Override
public void call(Subscriber<? super MyList> t) {
t.onNext(myList);
}
});
myObservable.observeOn(Schedulers.newThread()).subscribeOn(Schedulers.io()).subscribe(onNexAction);
}
So, what am I doing wrong here? How can I keep my observable emitting a new event as soon as there is a new object in MyList?
EDIT:
As suggested by Tassos Bassoukos, I applied the distinct() operator like this:
myObservable.observeOn(Schedulers.newThread()).subscribeOn(Schedulers.io()).distinct().subscribe(onNexAction);
But it doesn't solve my problem. Only the first added object is emitted.
This is a typical case for PublishSubject:
class MyList<T> {
final PublishSubject<T> onAdded = PublishSubject.create();
void add(T value) {
// add internally
onAdded.onNext(value);
}
Observable<T> onAdded() {
return onAdded;
}
}
MyList<Integer> list = populate();
Subscription s = list.onAdded()
.subscribe(v -> System.out.println("Added: " + v));
list.add(1); // prints "Added: 1"
list.add(2); // prints "Added: 2"
list.add(3); // prints "Added: 3"
s.unsubscribe(); // not interested anymore
list.add(4); // doesn't print anything
list.add(5); // doesn't print anything
According to your code, when an user click (on something), the onClickMethod is called.
this method will create an object myList and you'll build an item that will emit this object. Then you'll consume this object.
In fact, you'll just emit your list once, that's why you're only notify once (on one click)
To achieve what you're looking for, a possible way is to emit each item of your list when you add one.
private void onClickMethod() {
MyList myList = populateMyList();
myObservable = Observable.create(subscriber -> {
int currentSize = myList.size();
while(myList.size() != currentSize) {
subscriber.onNext(myList.getNext());
currentSize = myList.size();
}
subscriber.onCompleted();
});
myObservable.observeOn(Schedulers.newThread())
.subscribeOn(Schedulers.io())
.subscribe(item -> System.out.println(item));
}
Please note that this code is NOT performant as it will loop over myList.size() and you may encounter issue if someone add/remove items during the loop code.
A better approach would be to be notified when a new item is added in myList, then emit this new item.
First, the reason you are not getting more than one value from your observable is that the method that you pass to Observable.create is only called once, and that occurs when it is first subscribed to. If you want to just hook up your list as an observable the easiest way is to make MyList class implement Iterable and you can directly use from instead
private void onClickMethod() {
MyList myList = populateMyList();
Observable.from(myList)
.observeOn(Schedulers.newThread())
.subscribe(item -> System.out.println(item));
}