I have two Subjects, one subscribes to the other for updates.
Subject<Integer> subject = new Subject<>() {
#Override
public boolean hasObservers() {
return false;
}
#Override
public boolean hasThrowable() {
return false;
}
#Override
public boolean hasComplete() {
return false;
}
#Override
public Throwable getThrowable() {
return null;
}
#Override
protected void subscribeActual(Observer<? super InitialAPIResponse> observer) {
}
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Integer result) {
Log.d(TAG, "onNext: " + apiResponse);
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
};
subject.doOnNext(result -> Log.d("Subject", "accept: " + result));
observableSubject
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(subject);
observableSubject.onNext(1);
observableSubject.onComplete();
When the onNext() is called, the Consumer's accept() provided in doOnNext() is not. Even though according to the documentation
Observable.doOnNext()
Modifies the source ObservableSource so that it invokes an action when it calls onNext.
Scheduler:
doOnNext does not operate by default on a particular Scheduler
onNext
the action to invoke when the source ObservableSource calls onNext
return the source ObservableSource with the side-effecting behavior applied
From what I understand from the documentation the observable should call the Consumer in doOnNext().
I'm learning RxJava so maybe I'm doing something wrong here...
There are two problems:
1.
subject.doOnNext(result -> Log.d("Subject", "accept: " + result));
In above code, the result of doOnNext is not subscribed. doOnNext does not subscribe to upstream on its own, just as many other operators. Change to this, for example:
subject.doOnNext(result -> Log.d("Subject", "accept: " + result)).subscribe();
2.
observableSubject
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(subject);
observableSubject.onNext(1);
observableSubject.onComplete();
In above code, onComplete is called immediately after .onNext. This can cause timing issues when emitting the values.
Change above code to either
observableSubject
.subscribe(subject); // subscribe on the same thread so that everything happens sequentially.
observableSubject.onNext(1);
observableSubject.onComplete();
or
Subject<Integer> observableSubject = BehaviorSubject.create();
observableSubject
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(subject);
observableSubject.onNext(1);
// observableSubject.onComplete(); // don't call onComplete/
Related
There are two issues which I am currently facing.
1) As soon as the line RetrofitProvider.getInstance().getCurrentWeather(.....) is called the network call is being done. How can it be deferred till the observer is connected to it.
2) Once weatherInfoPublisher.onComplete() is called, the next time I call onComplete on this object the new observer's onNext is not getting called.
public Observable<LinkedList<WeatherInfo>> getWeatherData(final String payload, final TempUnit tempUnit) {
PublishSubject weatherInfoPublisher = PublishSubject.create();
RetrofitProvider.getInstance().getCurrentWeather(payload + ",us", translateTempUnit(tempUnit))
.flatMap(new Function<String, ObservableSource<String>>() {
#Override
public ObservableSource<String> apply(String todayResponse) throws Exception {
Log.d(TAG, "Received today weather: " + todayResponse);
parseTodayData(todayResponse, weatherDataList);
return RetrofitProvider.getInstance().getForecastWeather(
payload + ",us", translateTempUnit(tempUnit), FORECAST_DAYS);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<String>() {
#Override
public void onNext(String futureResponse) {
Log.d(TAG, "Received future weather: " + futureResponse);
parseFutureData(futureResponse, weatherDataList);
weatherInfoPublisher.onNext(weatherDataList);
weatherInfoPublisher.onComplete();
}
#Override
public void onError(Throwable e) {
Log.e(TAG, "The error is, " + e.getMessage());
}
#Override
public void onComplete() {
}
});
return weatherInfoPublisher;
}
This is a singleton class and the entire implementation has been provided in here in Github Link.
How can it be deferred till the observer is connected to it.
Do not subscribe to that observable in this method. Instead return that observable to the client. As soon as the observable is subscribed - a request would be performed.
the next time I call onComplete on this object the new observer's onNext is not getting called.
See reactive stream specs: if a stream completes - it can never be continued, that's a terminal event.
I am new in Rx android.When i try to call
Observable.from(imagesMulty).map(image -> printImage(image)).subscribe();
public void printImage(Image image)
{
Subscription addImage;
addImage = retrofit.create(Restapi.class).addImage(image)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Response<SlideResponse>>() {
#Override
public final void onCompleted() {
dismissProgress();
}
#Override
public final void onError(Throwable e) {
e.printStackTrace();
dismissProgress();
}
#Override
public void onNext(Response<SlideResponse> apiResponse) {
dismissProgress();
if (apiResponse.code() == 201) {
}
}
});
subscriptions.add(addSlide);
}
its showing No Instance of type variable R exist so that Observable conforms to Observable.Let me know whats is this error and how to resolve.My requirement is make api call one after other.
i tried to add compile "com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0" also but still error exist.
RxJava2 doesn't allow you to use Observable.from() function. Use are using com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0 with RxJava. (Version confliction)
Best implementation should be like this (in Rxjava2)
Disposable subscription;
subscription = Observable.just(imagesMulty)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
#Override
public void accept(#NonNull String s) throws Exception {
// do retrofit stuff
}
}, new Consumer<Throwable>() {
#Override
public void accept(#NonNull Throwable throwable) throws Exception {
throwable.printStackTrace();
}
});
subscription.dispose(); // Call in onDestroy() or onPause()
If you want to combine or zip your retrofit stuff with map operator, consider using zip, concat or combinelatest ...
you can try this example. This may help to solve your problem
https://github.com/dustin-graham/RxAndroid-Sample
I'm a newbie in RxJava and faced an issue as follows:
I have two Completable objects to store some data. I'd like to trigger the first one and later on start the second one only after the first one has finished with success. The call to the second Completable should be blocked until the first one has finished with success. Also, if the first one has finished with error, the other one should be also skipped.
Looking through documentation and other SO questions it seems that concatWith or andThen should work for me. But in both manual test and unit test I can see that the second completable is triggered in parallel to the first one :/
First completable
public Completable doA() {
Log.d(TAG, "class call");
return db.countRows()
.doOnSuccess(integer -> {
Log.d(TAG, "found rows: "+integer);
})
.doOnError(Throwable::printStackTrace)
.flatMapCompletable(this::customAction);
}
private Completable customAction(final int count) {
Log.d(TAG, "count: "+count);
if (count > 0) {
Log.d(TAG, "no rows, skip");
return Completable.complete();
}
final User user = ...
return db.save(user); // return Completable
}
Second Completable
public Completable doB() {
Log.d(TAG, "call to B");
// ...
}
Attempt to invoke B after A
public Completable someMethod() {
Log.d(TAG, "someMethod");
return doA()
.andThen(doB());
// this also doesn't work
//.concatWith(doB());
}
The subscription
someMethod()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnComplete(() -> {
Log.d(TAG, "complete");
// ...
})
.doOnError(throwable -> {
Log.d("Main", "error "+throwable.getMessage());
// ...
})
.subscribe();
When I run my app and check logs I can see:
D/Some method: some method
D/DoA: class call
D/DoB: class call // <- why here?
D/DoA: found rows: 0
D/DoA: count: 0
Also the following unit test fails:
#Test
public void test() {
when(doa.doA()).thenReturn(Completable.error(new Exception("test")));
observe(); // subscription with TestObserver
verify(dob, never()).doB(); // fails with NeverWantedButInvoked
}
What am I missing?
Because you called doB(). Let me rewrite your flow:
public Completable someMethod() {
Log.d(TAG, "someMethod");
// doA() inlined
LOG.d("class call");
Completable a = ...
// doB() inlined
Log.d("class call");
Completable b = ...
return a.andThen(b);
}
You can use andThen() or concatWith() operator.
Returns a Completable that first runs this Completable and then the other completable.
andThen()
firstCompletable
.andThen(secondCompletable)
In general, this operator is a "replacement" for a flatMap on Completable:
Completable andThen(CompletableSource next)
<T> Maybe<T> andThen(MaybeSource<T> next)
<T> Observable<T> andThen(ObservableSource<T> next)
<T> Flowable<T> andThen(Publisher<T> next)
<T> Single<T> andThen(SingleSource<T> next)
concatWith:
firstCompletable
.concatWith(secondCompletable)
Observable.create(new Observable.OnSubscribe<Integer>() {
#Override
public void call(Subscriber<? super Integer> subscriber) {
subscriber.onStart();
subscriber.onNext(1);
subscriber.onCompleted();
}
}).delaySubscription(5, TimeUnit.SECONDS).subscribe(new Subscriber<Integer>() {
#Override
public void onCompleted() {
Log.e("TAG", String.format("(%s) - onCompleted", System.currentTimeMillis()));
}
#Override
public void onError(Throwable e) {
Log.e("TAG", String.format("(%s) - onError", System.currentTimeMillis()), e);
}
#Override
public void onNext(Integer integer) {
Log.e("TAG", String.format("(%s) - onNext: %s", System.currentTimeMillis(), integer));
}
#Override
public void onStart() {
super.onStart();
Log.e("TAG", String.format("(%s) - onStart", System.currentTimeMillis()));
}
});
output:
(1485004553817) - onStart
(1485004558818) - onNext: 1
(1485004558819) - onCompleted
why onStart event not waiting to delaySubscription and calling soon ?
i want aware when call method called
Documentation says -
onStart -
This method is invoked when the Subscriber and Observable have been connected but the Observable has not yet begun to emit items or send notifications to the Subscriber.
delaySubscription:
Returns an Observable that delays the subscription to the source Observable by a given amount of time.
onNext is invoked only when the subscription is achieved. onStart is called the moment a connection is established. Thus, it works as expected according to the definition.
You can try commenting the code subscriber.onStart(); and execute the same again to notice that onStart is still called at the beginning. The intentional execution did not really invoke the said method because this was executed not on the real subscriber we created, but the one which was a result of delaySubscription (of type OnSubscribeDelaySubscription).
Below is a snippet which can probably help you achieve what you're looking for:
public static void main(String[] args) throws UnsupportedEncodingException, IOException {
Observable.timer(5, TimeUnit.SECONDS).flatMap(val -> {
System.out.println("Initialize");
return Observable.create(subscriber -> {
System.out.println("onsubscribe");
doMyAsyncStuff(subscriber);
});
}).subscribe(val -> System.out.println(val));
Observable.timer(10, TimeUnit.SECONDS).toBlocking().first();
}
We initialize a timer, once timer is executed, we perform some task in flatMap which should be the same as what you earlier did with onStart. Once that task is executed, we emit a Observable which emits all the elements that you could have consumed earlier with onNext calls.
Hello I am making observable to ask my server about its online/offline status every 15 seconds:
public Observable<Response> repeatCheckServerStatus(int intervalSec, final String path) {
return Observable.interval(intervalSec, TimeUnit.SECONDS)
.flatMap(new Func1<Long, Observable<Response>>() {
#Override
public Observable<Response> call(Long aLong) {
return Observable.create(new Observable.OnSubscribe<Response>() {
#Override
public void call(Subscriber<? super Response> subscriber) {
try {
Response response = client.newCall(new Request.Builder()
.url(path + API_ACTION_CHECK_ONLINE_STATUS)
.header("Content-Type", "application/x-www-form-urlencoded")
.get()
.build()).execute();
subscriber.onNext(response);
subscriber.onCompleted();
if (!response.isSuccessful())
subscriber.onError(new Exception());
} catch (Exception e) {
subscriber.onError(e);
}
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
});
}
After I call this method, first execution of code will be after intervalSec time (15sec in my case). Looking at rxJava docummentation of interval method:
http://reactivex.io/documentation/operators/interval.html
This is how it should be.
Question: is there any way to execute code instantly and then repeat in intervals?
You can execute it immediately also like this:
Observable.interval(0, 1000, TimeUnit.MILLISECONDS).subscribe();
What you are looking for is startWith
Observable.interval(15, SECONDS).startWith(1);
This will get the updates from the interval, but emit one item immediately after subscribing.
you can use `
Observable.interval(1, TimeUnit.SECONDS).startWith(0)
`
It is duplicate value "0" in subscribe.