Consider below code as I am not able to find better words to ask the question:
CompletionStage<Manager> callingAsyncFunction(int developerId) {
return getManagerIdByDeveloperId(developerId)
.thenCompose(id ->
getManagerById(id, mandatoryComputationToGetManager(id)))
}
mandatoryComputationToGetManager() returns a CompletionStage
Now the doubt which I have is :
I wanted to call mandatoryComputationToGetManager() and after its computation I want getManagerById(...) to be called.
I know there can be one way i.e. calling thenCompose() first to do mandatoryComputationToGetManager() and then do another thenCompose() on previous result for getManagerById(). But I wanted to figure out if there is a way without piping one thenCompose() o/p to another by which I can hold until mandatoryComputationToGetManager() result is ready.
As far as I understand, in the above code getManagerById() will get called even if the result is not yet ready from mandatoryComputationToGetManager(), which I want to wait for so that once mandatoryComputationToGetManager() give the result getManagerById() should get computed asynchronously.
Ideally, we should pipe one thenCompose o/p to another, but there is a way by which we can achieve what you are trying to do.
CompletionStage<String> callingAsyncFunction(int developerId) {
return getManagerIdByDeveloperId(developerId)
.thenCompose(id -> getManagerById(id, mandatoryComputationToGetManager()));
}
private CompletionStage<String> getManagerById(
Integer id, CompletionStage<String> stringCompletionStage) {
return stringCompletionStage.thenApply(__ -> "test");
}
private CompletionStage<String> mandatoryComputationToGetManager() {
return CompletableFuture.completedFuture("test");
}
Related
I have a Kotlin function from a separate library that takes a function as a parameter and gets the variable I need from the callback:
object Session {
fun get(callback: (accessToken: String?) -> Unit): Boolean {
SomeOtherClass(callback).get()
return true
}
}
Then to call it from another class I make the call (in java):
public String getToken() {
Session.INSTANCE.get((accessToken) -> {
// I want the method getToken() to be able to 'return accessToken;'
// but this call back returns Unit and the get method itself returns Boolean
});
}
Is there a way to return the variable accessToken from getToken() directly, or at least the equivalent value? Session.get is async so creating a "global" variable returns null because the value hasn't been assigned yet. This is one thing I have tried:
public String getToken() {
String temp;
Session.INSTANCE.get((accessToken) -> {
temp = accessToken;
});
return temp;
}
Relatively new to functional programming so any help is appreciated!
If the call to get the access token is async then you can't just grab right away. This is because the code inside the get call is running on another thread while your code keeps going. It would look like this:
public String getToken() {
String temp; // 1. you make a variable
Session.INSTANCE.get((accessToken) -> { // 2. get call starts processing
temp = accessToken;
});
return temp; // 3. now you return your uninitialized variable
}
and then after your function ends the token callback happens, but its to late, you already returned nothing. If you run it in a debugger with a break point on each line and keep running you will see the order that the code is executed and it may make more sense.
Your best bet is to just handle what you need in the callback rather than returning it in getToken()...
Not sure if you wanted an answer in kotlin or java but your code may look something like this in kotlin:
Session.get { token ->
onToken(token)
}
where onToken handles whatever code you needed the token for
fun onToken(token: String) {
// do whatever code you would've executed after getToken() here
}
Hope I explained that alright.
You can't return a callback's eventual result from the method that calls it without blocking the thread that made the call. The reason callbacks exist is so you won't block the thread that's making the call. On Android, your app will crash with an Application Not Responding message if you block the main thread for a few seconds.
If you use Kotlin, you can wrap library callbacks using suspendCancellableCoroutine to make them coroutine-compatible. Coroutine suspend functions do allow you to return delayed results.
I am new to Java Rx, I don't know if that is a valid question or not.
I have function
public Single<PayResponse> pay(PayRequest apiRequest) {
return client.initiatePayment(apiRequest)
.doOnSuccess(initiatePaymentResponse -> {
System.out.println("first");
client.confirmPayment(initiatePaymentResponse.getPaymentId())
.doOnSuccess(confirmPaymentResponse -> {System.out.println("second");doConfirmationLogic(confirmPaymentResponse ))}
.doOnError(ex -> {System.out.println("thirs");ex.printStackTrace();logError(ex);});
})
.doOnError(ex -> {ex.printStackTrace();logError(ex);});
}
after executing this method i can find first was printed twice but neither second nor third was printed
It is odd behaviour for me, because i expect to find first and second or third.
Any idea ?
In order to start receiving the emitted value(s) from an observable (like a Single<T>), you must subscribe() to it first.
You are probably only subscribing to the Single returned by pay twice somewhere else, and that's why you see first printed two times. In the code you show, I can see that are not subscribing to any of the observable there, so nothing will happen afterwards.
If you want to chain observables, the most common choice would be to use the flatMap operator (there are other options as well).
In your case, it would look similar to this:
public Single<PayResponse> pay(PayRequest apiRequest) {
return client.initiatePayment(apiRequest)
.flatMap(initiatePaymentResponse -> {
System.out.println("first");
return client.confirmPayment(initiatePaymentResponse.getPaymentId();
})
.flatMap(confirmPaymentResponse -> {
System.out.println("second");
return doConfirmationLogic(confirmPaymentResponse);
})
.doOnSuccess(confirmationLogicResponse -> System.out.println("third"))
.doOnError(ex -> {
ex.printStackTrace();
logError(ex);
});
}
Then, you subscribe to the single returned by pay somewhere else like this:
...
pay(apiRequest)
.subscribe(onSuccesValue -> {
// The whole chain was successful and this is the value returned
// by the last observable in the chain (doConfirmationLogic in your case)
}, onError {
// There was an error at some point during the chain
}
...
I am supposing that all the methods initiatePayment, confirmPayment, doConfirmationLogic return Singles and that doConfirmationLogic ends up returning a Single<PayResponse>. If that's not the case, you will need to make some small changes, but you get the general idea of how chaining observables work.
I have a remote call(retrofit) - which I converted into an Observable. Let's call it Observable Y.
Now, I also have a certain code that looks for geo location with GPS and NETWORK providers. I have a Timer there, that basically limits the time that the geo search can be performed for. Let's call it Task X. I want to convert it into an Observable X.
Then, I want to have a subcription, that will perform Observable X(that is, find location), once it will return a Location, I will "analyze" in a certain way, and then I will either pass that Location into the Observable Y(the retrofit call), or simply quit(if that "raw" location will be enough in my case)
At ALL time, I want to be able to interrupt all that "process". From what I gather, I can achieve that by simply unsubscribing the subscription, right?
and then next time just subscribe this subscription once again in the future.
Questions:
1. Can all of that be implemented via RxJava/RxAndroid ?
2. Does it even make sense implementing it with Rx ? or is there a more efficient way?
3. How is it done with Rx?
(More specifically : (a) How do I convert task Y into an Observable Y?
(b) How do I perform them in sequence with only one subscription?)
1- It can be implemented via RxJava
2- This is your best option so far
3-
3-a Observable.fromCallable() does the trick
3-b flatmap operator is used to chain observable calls
you can proceed like this:
private Location searchForLocation() {
// of course you will return not null location
return null;
}
// your task X
//mock your location fetching
private Observable<Location> getLocationObservableX() {
return Observable.fromCallable(() -> searchForLocation());
}
//your task Y
//replace CustomData with simple String
//just to mock your asynchronous retrofit call
private Observable<List<String>> getRetrofitCallObservableY(String param){
return Observable.just(new ArrayList<String>());
}
//subscribe
private void initialize() {
getLocationObservableX()
.filter(location -> {
//place your if else here
//condition
//don't continue tu retrofit
boolean condition = false;
if (condition) {
//process
//quit and pass that Location in Broadcas
//you shall return false if you don't want to continue
return false;
}
return true;
})
//filter operation does not continue here if you return false
.flatMap(location -> getRetrofitCallObservableY("param"))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> {
//do what you want with response
});
}
I have a method which accepts Mono as a param.
All I want is to get the actual String from it. Googled but didn't find answer except calling block() over Mono object but it will make a blocking call so want to avoid using block(). Please suggest other way if possible.
The reason why I need this String is because inside this method I need to call another method say print() with the actual String value.
I understand this is easy but I am new to reactive programming.
Code:
public String getValue(Mono<String> monoString) {
// How to get actual String from param monoString
// and call print(String) method
}
public void print(String str) {
System.out.println(str);
}
Getting a String from a Mono<String> without a blocking call isn't easy, it's impossible. By definition. If the String isn't available yet (which Mono<String> allows), you can't get it except by waiting until it comes in and that's exactly what blocking is.
Instead of "getting a String" you subscribe to the Mono and the Subscriber you pass will get the String when it becomes available (maybe immediately). E.g.
myMono.subscribe(
value -> System.out.println(value),
error -> error.printStackTrace(),
() -> System.out.println("completed without a value")
)
will print the value or error produced by myMono (type of value is String, type of error is Throwable). At https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html you can see other variants of subscribe too.
According to the doc you can do:
String getValue(Mono<String> mono) {
return mono.block();
}
be aware of the blocking call
Finally what worked for me is calling flatMap method like below:
public void getValue(Mono<String> monoString)
{
monoString.flatMap(this::print);
}
What worked for me was the following:
monoString.subscribe(this::print);
Simplest answer is:
String returnVal = mono.block();
This should work
String str = monoString.toProcessor().block();
Better
monoUser.map(User::getId)
Using RxJava I have an Observable<A> and an Observable<B>. I want to start subscription on B as soon as the first (and only) element of A is emitted. I know I can chain it like this:
final Observable<A> obsOfA;
final Observable<B> obsOfB;
obsOfA.subscribe(new Action1<A>() {
#Override
public void call(A a) {
obsOfB.subscribe(...)
}
});
..But this will cause a nesting syntax which gets ugly as soon as we introduce Observable<C>. How can I "unwrap" the syntax to a more fluent one - getting one that is more like the javascript Promise.then()-flow?
You should use flatMap:
obsOfA.flatMap(new Func1<A, Observable<B>>() {
#Override
public Observable<B> call(A a) {
return obsOfB;
}
})
.subscribe(/* obsOfB has completed */);
Every time obsOfA calls onNext(a), call will be executed with this value a.
You can use switch, combined with map in switchMap:
obsOfA.switchMap(i -> obsOfB)
.subscribe(/* obsOfB has completed */);
This does almost the same as merge in flatMap as long as obsOfA only yield 1 value, but when it yield more values, flatmap will combine them, while switch will only be subscribed to the last instance of obsOfB. This might be useful when you need to switch to a different stream.