Emit a value after onNext is called after a particular time - java

I want to emit a random value 10 secs after onNext is called. So onNext will be called for 12345 and 10 secs later onNext should be called for a random number. What is the best way to achieve this using RxJava? Thanks in advance.
Observable.create(subscriber -> {
subscriber.onNext(12345);
}).subscribeOn(...)
.observeOn(...)
.subscribe(new Subscriber<Long>(){
#Override
public void onNext(Long aLong) {
//Do Something
}
})

If you emit your '12345' value right away, then solution is trivial. Just merge this observable with timer and you will get this kind of behavior. However, I am going to assume that your logic in OnSubscribe method you pass to create is doing some work and will emit the value once it is ready ( i.e. network request ). In that case, you need leverage both flatMap and merge operators. Something like this should suffice.
Observable.create(subscriber -> {
subscriber.onNext(12345);
})
.flatMap(value -> Observable.just(value)
.mergeWith(Observable.timer(10, TimeUnits.SECONDS).map(/* define your "random" value here */))
)
.subscribeOn(...)
.observeOn(...)
.subscribe(new Subscriber<Long>(){
#Override
public void onNext(Long aLong) {
//Do Something
}
})
It will take your value and convert it into and observable, which emits this value right away and starts a timer for 10 seconds to emit something else.
Note: Beware that this will take every item your observable emits and create this delayed second response for each of them. So if you plan on emitting multiple values from your source observable, you need to take this into account.

Related

What's the easiest way to wait for Mono completion in the background?

We are given a Mono, that's handling some action(say a database update), and returns a value.
We want to add that Mono(transformed) to a special list that contains actions to be completed for example during shutdown.
That mono may be eagerly subscribed after adding to the list, to start processing now, or .subscribe() might not be called meaning it will be only subscribed during shutdown.
During shutdown we can iterate on the list in the following way:
for (Mono mono : specialList) {
Object value = mono.block(); // (do something with value)
}
How to transform the original Mono such that when shutdown code executes, and Mono was previously subscribed(), the action will not be triggered again but instead it will either wait for it to complete or replay it's stored return value?
OK, looks like it is as simple as calling mono.cache(), so this is how I used it in practice
public Mono<Void> addShutdownMono(Mono<Void> mono) {
mono = mono.cache();
Mono<Void> newMono = mono.doFinally(signal -> shutdownMonos.remove(mono));
shutdownMonos.add(mono);
return newMono;
}
public Function<Mono<Void>,Mono<Void>> asShutdownAwaitable() {
return mono -> addShutdownMono(mono);
}
database.doSomeAction()
.as(asShutdownAwaitable)
.subscribe() // Or don't subscribe at all, deferring until shutdown
Here is the actual shutdown code.
It was also important to me that they execute in order of being added, if user chose not to eagerly subscribe them, that's reason for Flux.concat instead of Flux.merge.
public void shutdown() {
Flux.concat(Lists.transform(new ArrayList<>(shutdownMonos), mono -> mono.onErrorResume(err -> {
logger.error("Async exception during shutdown, ignoring", err);
return Mono.empty();
}))
).blockLast();
}

How to return the variable "a" in the function below

It's a simplified function.
It keeps returning 0 while I expect this to return 5. How come?
public int accessKey() {
a = 0;
mSubscription = mAccountManager.getLoginPassword()
.flatMap(loginPassword -> mServerAPI
.getProfilesList((new BaseRequest(
loginPassword.getLogin(),
loginPassword.getPassword(),
ClientGetter.getClientFromManager(),
CodeSnippets.getSha256(ClientGetter.getClientFromManager()))
)))
.doOnNext(profilesListe -> mProfilesList = profilesListe.getItems())
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<BaseResponse>() {
#Override
public void onCompleted() {
a =5;
}
return a; }
It's because of the asynchronous or non blocking behaviour , Normally during the scenarios of API calls fetching some data from database ,these behaviours we handle asynchronously,because otherwise your application will get stuck This post will help you to solve this matter. Refer this
you're executing an asynchronous operation here. your code doesn't execute "top down" here but will be executed on a different thread - Rxjava shifts this entire operation over to another thread and then returns the result to the thread specified, but this doesn't happen immediately. by the time your subscribe code has executed (we don't know when that will be) your return statement has already executed.
you could try change your code to something like this (just as an idea, i don't have any code similar to yours to create a working example):
return mAccountManager.getLoginPassword()
.flatMap(loginPassword -> mServerAPI
.getProfilesList((new BaseRequest(
loginPassword.getLogin(),
loginPassword.getPassword(),
ClientGetter.getClientFromManager(),
CodeSnippets.getSha256(ClientGetter.getClientFromManager()))
)))
.doOnNext(profilesListe -> mProfilesList = profilesListe.getItems())
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
this means that your method will now return an observable, which you can then subscribe on and subscribe to those changes where they are used.
this means that the signature of your method will have to change to support this new return type and the calling method will have to subscribe to this observable.
you describe your question as a simplified function, but I'll give you an even simpler (complete) example:
public Observable<Integer> foo() {
return Observable.just(5);
}
public void usage(){
Disposable disposable = foo().subscribeOn(something).observeOn(something).subscribe(
//inside this subscribe, like you'd normally do, you'd find the result of 5
)
...
//handle disposable
}
I used the Callback interface method and it worked! Many thanks

RxJava polling + manual refresh

I have a list a want to refresh every minute.
For example the user list here : https://github.com/android10/Android-CleanArchitecture/blob/master/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserList.java
I add a periodical refresh using repeatWhen :
public Observable<List<User>> buildUseCaseObservable(Void unused) {
return this.userRepository
.users()
.repeatWhen(new Function<Observable<Object>, ObservableSource<?>>() {
#Override
public ObservableSource<?> apply(Observable<Object> objectObservable) throws Exception {
return objectObservable.delay(1, TimeUnit.MINUTES);
}
});
}
It works fine this way, calling onNext every minute.
But if I want to refresh immediately this list (because of user's action or because of a notification), I don't know how to perform that.
Should I cancel/dispose the observable and restart a new one ?
Thanks
From your code I understand that the users list is generated and emitted upon subscription.
Here are some solutions I can think of, instead of unsubscribing and resubscribing upon the event to which you want to react immediately:
Instead of using the repeatWhen operator, use the interval creation operator combined with the flatMap to invoke the subscription to a new Observable every minute and use the merge operator to add reaction to the other event in which you are interested. Something like this:
#Test
public void intervalObservableAndImmediateReaction() throws InterruptedException {
Observable<String> obs = Observable.interval(1, TimeUnit.SECONDS)
.cast(Object.class)
.mergeWith(
Observable.just("mockedUserClick")
.delay(500, TimeUnit.MILLISECONDS))
.flatMap(
timeOrClick -> Observable.just("Generated upon subscription")
);
obs.subscribe(System.out::println);
Thread.currentThread().sleep(3000); //to see the prints before ending the test
}
or adjusted to your needs (but the principal is the same):
Observable.interval(1, TimeUnit.MINUTES)
.mergeWith(RxView.clicks(buttonView))
.flatMap(timeOrClick -> this.userRepository.users());
You can use the flatMap operator as before, even while keeping you working current implementation and without merging to an interval - just keep your working code and in another area of the programme chain it to the RxBinding of your choosing:
RxView.touches(yourViewVariable)
.flatMatp(motionEvent -> this.userRepository.users())
.subscribe(theObserver);
Note that in this solution the subscription is done independently to the two observables. You'll probably be better off if you use different observers, or manage a subject or something on that line. A small test I ran showed one subscriber handled subscribing to 2 different observables with no problem (in Rxjava1 - didn't check in Rxjava2 yet), but it feels iffy to me.
If you aren't concerned with adjusting the refresh time after one of the other observables emits data you can do something like the following:
// Specific example of a user manually requesting
val request = Observable.create<String> { emitter ->
refresh.setOnClickListener {
emitter.onNext("Click Request")
}
}
.observeOn(Schedulers.io())
.flatMap {
userRepository.users()
}
// Refresh based off of your original work, could use something like interval as well
val interval = userRepository.users()
.subscribeOn(Schedulers.io())
.repeatWhen { objectObservable ->
objectObservable.delay(1, TimeUnit.MINUTES)
}
// Combine them so that both emissions are received you can even add on another source
Observable.merge(request,interval)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
contents.text = it.toString()
}, {
contents.text = it.toString()
},{
println(contents.text)
})
Then you don't have to dispose and resubscribe every time

RxJava: How to repeat an observable chain when original condition is not met anymore?

I'd like to re-subscribe to an observable using repeat(), but the condition that triggers the original observable is not met anymore when the first subscription is finished. How would I re-subscribe the observer in this case?
The code looks something like this:
RxInput.onInput(grid)
.flatMap(Grid::handle)
.flatMap(Grid::check)
.delay(300, TimeUnit.MILLISECONDS)
.flatMap(Grid::clean)
.repeat() // Does not work
.subscribe(g -> {System.out.println("Finished");});
The code of RxInput.onInput() is like this:
public static <T> Observable<T> onInput(T t) {
return Observable.create(subscriber -> {
if(InputSystem.isInputOn()) { // This is not true anymore when re-subscribing
subscriber.onNext(t);
}
});
}
Given that you seem to want to prevent emissions from initial subscription if isInputOn is false then define the observable like this:
Observable.defer(
() -> {
if (!InputSystem.isInputOn())
return Observable.empty();
else
return yourInput
.flatMap(Grid::handle)
.flatMap(Grid::check)
.delay(300, TimeUnit.MILLISECONDS)
.flatMap(Grid::clean)
.repeat();
})
.subscribe(...);
A quick extra note, do your damndest to avoid using Observable.create like in your example above. If you do emit things like that then you need to combine your observable with .onBackpressureXXX() because you may get a MissingBackpressureException from operators like flatMap downstream.

How do you show spinner if RxJava observable takes to long?

I feel like someone has to have tried this, but I can't figure out a nice way to do something if an observable takes to long.
This is the flow I want.
Start a search.
If the search takes longer than some time,
show a spinner or show progress bar.
When finished do subscription action and hide spinner/progress bar.
The closest I can think of is like a Zip
manager.search(searchTerm)
.zip(Observable.Timer(1, TimeUnit.SECONDS))
.subscribe(
// if the search is non null then we are good
// if the long time is non 0 we need to show spinner
);
Is there something better to do? I have been trying all day with no success. In a perfect world I feel like I would want something like
manager.search(searchTerm)
.timeout(i -> /* do timeout stuff */, 1, TimeUnit.SECONDS)
.subscribe(item -> /* do search result stuff */);
You can do this by publishing the search Observable through the timeout:
Observable<Integer> source = Observable.just(1).delay(5, TimeUnit.SECONDS);
source
.doOnSubscribe(() -> System.out.println("Starting"))
.publish(o ->
o.timeout(1, TimeUnit.SECONDS, Observable.<Integer>fromCallable(() -> {
System.out.println("Spinning...");
return null;
})).ignoreElements().mergeWith(o)
)
.toBlocking()
.subscribe(v -> {
System.out.println("Hide spinner if shown.");
System.out.println(v);
});
This works by splitting the source into two hot lanes: the first lane will run a timeout operator which when times out, starts another Observable with the side-effect that shows the spinning control. One of the ways is to use fromCallable for this and ignore its result (this also avoid duplication). The second lane will be unchanged and merged with the timeout lane to deliver the actual value.
Today i found a bit odd but working solution. Idea is to use interval instead of timer.
fun <T> base_delayed_progress_observable(source: Observable<T>): Observable<T>
{
val timer = Observable.interval(100, TimeUnit.MILLISECONDS) //Creates observable that will emit Long++ each 100 miliseconds
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(
{
if (it == 10L)//Here we check current timer value. For example here i check if it is 1 second gone (100 miliseconds * 10 = 1 second)
{
//here we put all we need to show progress/spinner an so on
}
})
return Observable.zip(source, timer,
BiFunction<T, Long, T> { t1, t2 ->
//Here we return our original Obervable zipped with timer
//Timer will be cancelled when our source Observable gets to OnComplete
return#BiFunction t1
}).doFinally(
{
//Here we can dismiss all progress dilogs/spinner
})
}

Categories

Resources