rxjava onStart event with delaySubscription - java

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.

Related

Consumer.accept() not called for Subject in doOnNext()

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/

Make multiple asynchronous calls(fire and forget calls) at once using Rx java Observable

I have a list of downstream api calls(about 10) that I need to call at once asynchronously. I was using callables till now where I was using
List<RequestContextPreservingCallable <FutureResponse>> callables
I would add the api calls to this list and submit it at the end using executeAsyncNoReturnRequestContextPreservingCallables.
Using Rx java Observables how do I do this?
List<RequestContextPreservingCallable<FutureResponse>> callables = new
ArrayList<RequestContextPreservingCallable<FutureResponse>>();
callables.add(apiOneConnector.CallToApiOne(name));
callables.add(apiTwoConnector.CallToApiTWO(sessionId));
....
//execute all the calls
executeAsyncNoReturnRequestContextPreservingCallables(callables);
You could make use of the zip operator. The zip operator can take multiple observables and execute them simultaneously, and it will proceed after all the results have arrived.
You could then transform these result into your needed form and pass to the next level.
As per your example. Say you have multiple API calls for getting name and session etc, as shown below
Observable.zip(getNameRequest(), getSessionIdRequest(), new BiFunction<String, String, Object>() {
#Override
public Object apply(String name, String sessionId) throws Exception {
// here you will get all the results once everything is completed. you can then take these
// results and transform into another object and returnm from here. I decided to transform the results into an Object[]
// the retuen type of this apply funtion is generic, so you can choose what to return
return new Object[]{name, sessionId};
}
})
.subscribeOn(Schedulers.io()) // will start this entire chain in an IO thread
.observeOn(AndroidSchedulers.mainThread()) // observeOn will filp the thread to the given one , so that the downstream will be executed in the specified thread. here I'm switching to main at this point onwards
.subscribeWith(new DisposableObserver<Object>() {
#Override
public void onNext(Object finalResult) {
// here you will get the final result with all the api results
}
#Override
public void onError(Throwable e) {
// any error during the entire process will be triggered here
}
#Override
public void onComplete() {
//will be called once the whole chain is completed and terminated
}
});
You could even pass a list of observables to the zip as follows
List<Observable<String>> requests = new ArrayList<>();
requests.add(getNameRequest());
requests.add(getSessionIdRequest());
Observable.zip(requests, new Function<Object[], Object[]>() {
#Override
public Object[] apply(Object[] objects) throws Exception {
return new Object[]{objects[0], objects[1]};
}
}).subscribeWith(new DisposableObserver<Object[]>() {
#Override
public void onNext(Object[] objects) {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
})

How to implement an interrupted thread in rxjava?

I have the following code that I want to turn Reactive:
class ReadThread extends Thread {
#Override
public void run() {
super.run();
while(!isInterrupted()) {
try {
String result = doBlockingIO();
listener.onReceivedData(result);
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
And if I want to stop I/O operation I call
readThread.interrupt();
My initial rxjava2 implementation is as per bellow:
mCompositeDisposable.add(Maybe.fromCallable(() -> {doBlockingIO();}))
.repeat()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new ResourceSubscriber<String>() {
#Override
public void onNext(String data) {
onReceivedData(data);
}
#Override
public void onError(Throwable e) {
onErrorOccurred(e);
}
#Override
public void onComplete() {
// do nothing
}
}));
As this is an Android application, on my onStop() Activity callback I call dispose() on the composite disposable above.
Running the above rxjava2 code on certain devices has some weird side effects, as when I stop IO Activity and move to another Activity that is also using similar composite disposable and IO operations, some operations seem to freeze. Also by looking at some logs I can tell that rxjava2 Thread running doBlockingIO completes after I leave and come back to the IO Activity:
07-21 19:18:17.420 5774-434/com.mobile.installation E/IOActivity: doBlockingIO() -> PRE RxCachedThreadScheduler-5 --->> LEFT ACTIVITY
07-21 19:18:30.134 5774-565/com.mobile.installation E/IOActivity: doBlockingIO() -> PRE RxCachedThreadScheduler-6 --->> RE-ENTERED ACTIVITY
07-21 19:18:30.847 5774-434/com.mobile.installation E/IOActivity: doBlockingIO() -> POST RxCachedThreadScheduler-5
Any idea on how to implement the typical java IO interrupt scenario properly with rxjava2?
Many thanks in advance!

Android Firebase - Remove listeners from Task<T>

I defined this method, in MyActivity class that allow me to download in memory some data from a Firebase storage.
public void submitDownload() {
Task<byte[]> downloadTask=FirebaseStorage.getInstance.
getReference(DATA_PATH_TO_DOWNLOAD).getBytes(MAX_BYTES);
isTaskActive=true;
//remove eventually a previous callback from the handler
timeoutHandler.removeCallbacks(timeoutCallback);
downloadTask.addOnSuccessListener(MyActivity.this, onSuccessListener);
downloadTask.addOnFailureListener(MyActivity.this, onFailureListener);
timeoutHandler.postDelayed(timeoutCallback, 5000);
}
This is, instead, the onCreate() method:
protected void onCreate() {
super.onCreate();
onSuccessListener=new OnSuccessListener<byte[]>() {
public void onSuccess(byte[] bytes) {
if(isTaskActive) {
isTaskActive=false;
Log.d("DOWNLOAD_TASK", "SUCCESS");
}
}
};
onFailureListener=new OnFailureListener() {
public void onFailure(Exception e) {
if(isTaskActive) {
isTaskActive=false;
Log.d("DOWNLOAD_TASK", "FAILURE");
}
}
};
timeoutHandler=new Handler();
timeoutCallback=new Runnable() {
public voi run() {
if(isTaskActive) {
isTaskActive=false;
Log.d("DOWNLOAD_TASK", "TIMEOUT");
submitDownload(); //retry download
}
}
};
submitDownload();
}
Obviously, onSuccessListener, onFailureListener, timeoutHandler, timeoutCallback and isTaskActive are instance variable.
As you can see in the run() method defined in timeoutCallback, in addition to a log message, is also called the sumbitDownload(). Pratically, if a timeout occurs and the task is still active, a new download is started.
Now, imagine this scenario.
When Activity is created, a download task is started. Suppose that downloadTask doesn't complete, and neither onSuccessListener nor onFailureListener are called, but timeout occurs. So, from the run() method of timeoutCallback a new download is started.
Now, what happens to the previous downloadTask? Is it canceled? Is it replaced by the current task? or does it continue to be active and potentially could trigger its attached listeners?
If the latter question is true, how to remove the listeners from a Task<T> object?
Does the getResult() method, however, complete (i.e finish) the task?

Keep stream alive even after onComplete()

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.

Categories

Resources