OkHttp library Callback interface is declared as
public interface Callback {
void onFailure(Request request, IOException e);
void onResponse(Response response) throws IOException;
}
Unhandled exceptions from onResponse method will get eaten up by Call class as I have recently discovered in Callback failure for cancelled call in OkHttp
I have few questions related to that design.
First, wouldn't it be better have different declaration of onResponse method in order to force catching exceptions in onResponse rather than throwing them, since they will be eaten up.
Is this design flaw in OkHttp Callback interface or is this kind of code common practice in Java?
Second, when http request reaches onResponse callback method I would expect that canceling request at that point should be prohibited. I would say this is a bug. Am I right?
I'm also struggling with this, for now I've solved it as follows:
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, final IOException e) {
runOnUiThread(new Runnable() {
#Override
public void run() {
// AlertDialog, etc.
}
});
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
onFailure(call, new IOException("Unexpected code: " + response));
}
// else success
}
});
The key point is calling OnFailure inside OnResponse. I wasn't able to access the Exception in any other way (though there probably are other ways; this gives OnFailure some additional usefulness in my opinion, and it conveys intent fairly well I think). Note that OnFailure can be called for other reasons: https://square.github.io/okhttp/2.x/okhttp/com/squareup/okhttp/Callback.html
Related
I have an HTTP request that triggers a long-running task (multiple HTTP requests to another service) that is supposed to be completed in the background while the original requests complete.
So what I do is
public void triggerWork(#RequestBody SomeObject somObject) {
return new ResponseEntity<>(startWorkAndReturn(somObject), HttpStatus.OK);
}
public void startWorkAndReturn(SomeObject someObject) {
Observable.create(observableEmitter -> {
// do the work with someObject here and at some time call
observableEmitter.onNext("result");
}).subscribe(new Observer<Object>() {
#Override
public void onSubscribe(Disposable disposable) {
}
#Override
public void onNext(Object o) {
// called at some unknown time
}
#Override
public void onError(Throwable throwable) {
}
#Override
public void onComplete() {
// currently not used as all the work is done in onNext but maybe that's a mistake
}
});
return;
}
But this seems to block the request until all the work has been done. Which already seems odd to me, since I never call onComplete, which in itself might be a mistake. But still, I am wondering how to create a request that immediately returns after triggering a background worker.
Is Flowables the solution here? I am going to refactor to those anyways to handle backpressure. Or do I need to create a background worker Thread? What is the best practice here?
Thanks
I would use Observable.fromCallable{} since you need emit only single event. That will handle onCompleate call. From information you share I don`t know how can you properly handle disposable. You should add subscribeOn() and observeOn() operators that will define on which thread 'work' should be processed and result should be observed.
Docs ref:
http://reactivex.io/RxJava/javadoc/io/reactivex/Observable.html#fromCallable-java.util.concurrent.Callable-
http://reactivex.io/documentation/operators/subscribeon.html
http://reactivex.io/documentation/operators/observeon.html
We are using Akka framework for inter process communication. Some days back QA team identified some requests which got stuck in limbo. For some requests both onSuccess() and onFailure() callback methods were not called. The last line of log showed
"Charging Customer."
and the flow for that particular transaction stopped there. The next log should be either
"Charging response or Charging Failed"
What could be the reason for such behaviour? Could it be due to the dispatcher getting choked? We are using the default dispatcher.
Code
log.debug("Charging Customer");
Future future = Patterns.ask(actorSelection, new Gson().toJson(request), timeout);
future.onSuccess(new onChargingSuccess<>(ccRequest), context().system().dispatcher());
future.onFailure(new onFailureHandler(ccRequest), context().system().dispatcher());
private class onChargingSuccess<T> extends OnSuccess<T> {
#Override
public void onSuccess(T t) throws Throwable {
log.debug("Charging response:" + t.toString());
}
private class onFailureHandler extends OnFailure {
#Override
public void onFailure(Throwable thrwbl) throws Throwable {
log.info("Charging Failed");
}
Well its not really a solution but restarting the module fixed the issue. The module was running for an year. I know this makes it a very general question now but i'll keep it here just in case we dig down the actual issue and find the solution. I'll update in that case.
I need to save the response variable from a request, areaRequest is a RequestContext this works but i can't save it and use it out of the scope
Long temp;
areaRequest.countByCurrentInstitution().fire(new Receiver<Long>() {
#Override
public void onSuccess(Long response) {
temp = response;
}
});
You can't use outside non-final variables inside the Receiver.
A quick and dirty change just to avoid the scope problem would be:
final Long[] temp = {-1};
areaRequest.countByCurrentInstitution().fire(new Receiver<Long>() {
#Override
public void onSuccess(Long response) {
temp[0] = response;
}
});
doSomethingWith(temp[0]);
But that is usually NOT what you want to do. Because (if) countByCurrentInstitution() is an asynchronous call, temp[0] would still be -1 by the time you invoke doSomethingWith(), since the async method is still running in another thread.
You can make your main thread wait a bit by using a simple Thread.sleep() or (yikes!) a very long loop but, again, that's just a quick hack and prone to errors (what if the call takes longer than that?).
The best option is to ditch Long temp and just move your code inside the onSuccess() method:
areaRequest.countByCurrentInstitution().fire(new Receiver<Long>() {
#Override
public void onSuccess(Long response) {
doSomethingWith(response);
}
});
Well, after work a lot of time with GWT the solution that I found to this was create nested async calls.
areaRequest.countByCurrentInstitution().fire(new Receiver<Long>() {
#Override
public void onSuccess(Long response) {
// Here I pass the value from the first request
anotherRequest.anotherFunction(response).fire(new Receiver<Long>(){
#Override
public void onSuccess(Long new_response){ // Long again it could be anything it depends of your function
doWhateverYouWant(new_response)
}
});
}
});
We are using RxAndroid + retrofit for our api calls.
I sort of understand why any exceptions within the sequence will pass the Throwable through onError().
But how do you end the sequence, how do you then process a response and return to throwing fatal exceptions again? I would have expected processing in onCompleted() would allow this, but I'm still seeing onError() being called.
Simplified snippet below. Gives the result -
throwable: Attempt to invoke virtual method 'boolean java.util.ArrayList.add(java.lang.Object)' on a null object reference
Observable<ResponseModel> observable = getApiCallObservable();
AppObservable.bindFragment(this, observable)
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ResponseModel>() {
#Override
public void onCompleted() {
uninitializedList.add("item");
}
#Override
public void onError(Throwable e) {
Log.e(TAG, "throwable: " + e.getMessage());
}
#Override
public void onNext(ResponseModel response) {
}
});
thanks for any help
I'm not sure i understood what is being asked here. Basically, if your Observable getApiCallObservable() throws an error, onError will be called and you should handle the error accordingly in onError. If that happens, as it is, nothing will happen anymore. If an error happens, onError is called and stream end. If there is no error, onNext is called, and that's where you should do anything with your response. After onNext, finally, onCompleted is called.
The error that is showing is simply saying that your arraylist uninitializedList is null, so the method call add() is invalid.
Edit. I think i got your point now. You want handle the error without onError being called by the observable. Move your oncomplete code to onNext, and it won't fall under onError, it will throw the fatal exception. is that it?
When a called the persist() method from server, a exception is throwed after a validation in uniques of a email.
The problem is that onSuccess method from client is called, instead of onFailure. Here is the code.
RequestContext req = driver.flush();
if (req.isChanged() && !driver.hasErrors()) {
saveButton.setEnabled(false);
req.fire(new Receiver<Void>() {
#Override
public void onSuccess(Void response) {
//anything
}
#Override
public void onFailure(ServerFailure error) {
//anything
}
});
}
public User persist() throws GenericException{ // extends from Exception
//query in database
throw new GenericException("Email must be unique");
//save case is correct
}
Any help?
Why do you think that throwing exception == calling onFailure method? Did you analyzed code - is somewhere exception handler that catches your exceptions and converts them to onFaliure calls?