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)
}
});
}
});
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
My english is not the best, so I apologize in advance for that.
My situation is the following, I am developing an Android app and I have an async task, and in the doInBackground method have the following code:
#Override
protected Boolean doInBackground(String... params) {
getFirebaseUserChannels(new ResultListener<List<Channel>>() {
#Override
public void finish(List<Channel> firebaseUserChannels) {
if (firebaseUserChannels.isEmpty()) {
getFirebaseChannels(new ResultListener<List<Canal>>() {
#Override
public void finish(List<Channel> firebaseChannels) {
saveChannelsSQLDatabase(firebaseChannels);
saveChannelsFirebaseDatabase(firebaseChannels);
}
});
} else {
saveChannelsSQLDatabase(canalesUsuarioFB);
}
}
});
return true;
}
So, the method "getFirebaseUserChannels" is an async method that in response throws a list, and when that list is ready to use it, I have to evaluate it and use it.
But as you know, java executes the async method and continues until the return.
I want that the "doInBackground" does not continue the execution until all the async methods executions ends.
So, How Could I do that? How is the best way to manage this situation?
How is the best way to manage this situation?
Get rid of the AsyncTask entirely. Have whatever code was going to execute the AsyncTask simply call getFirebaseUserChannels().
I know there are probably a couple ways to do this, just looking for the most efficient and concise way to go about it:
public Object giveMeNewObject() {
final Object result = null;
SomeApiClient.start(new Callback() { // starts an async process
#Override
public void onSuccess(Object somethingNew) {
result = somethingNew; //ERROR; can't set cause final
}
});
return result; //result is null, cause Async already finished
}
From your code - this is modified on fly so correct mistakes and all will work as you expect - caller will wait untill 3rd party finishes the processing and will get the result of that process:
public Object giveMeNewObject() {
CountDownLatch latch=new CountDownLatch(1);
Callback callback=new Callback() {
public sometype result=null;
#Override
public void onSuccess(Object somethingNew) {
result = somethingNew; //ERROR; can't set cause final
latch.countDown();
}
});
SomeApiClient.start(callback);
latch.await(sometimetowait);
return callback.result;
}
Read the documentation of AsyncTask. Your job should be done in doInBackground method and the result should be returned by that method. Later on you can use get(Timeout) method to retrieve that returned value. get will even block if the computation in doInBackground is not complete yet for given ammount of the time.
You can find tons of examples of how to use async task. One of them is in the API documentation (link above)
I have a small Spring Boot app waiting for REST calls to start an async job. However what I'd like to do next is get results of those async jobs and store them in DB. But I don't know how to use object returned with Future asynchronically.
Here is more or less what I have:
#RequestMapping("/vlan/{id}/{name}")
public void performVLANConfig(#PathVariable("id") int id, #PathVariable("name") String name) {
logger.debug("Received req");
Future<ProcessedRequest> processedRequestFuture= asyncService.processVlan(id, name);
processedRequestRepository.save(processedRequest);
}
But now it just waits for async call to end. Is there any way to let the async method live its life and after it has completed store this completition error?
You need to attach a callback. If you using Future then you can't attach a callback to it, assign to a ListenableFuture instead, the service needs to return a ListenableFuture of course.
ListenableFuture<ProcessedRequest> future = asyncService.processVlan(id, name);
future.addCallback(new ListenableFutureCallback<ProcessedRequest>() {
#Override
public void onFailure(Throwable throwable) {
// deal with it
}
#Override
public void onSuccess(ProcessedRequest processedRequest) {
processedRequestRepository.save(processedRequest);
}
});
I'm using Square's Retrofit Client to make short-lived json requests from an Android App. Is there a way to cancel a request? If so, how?
For canceling async Retrofit request, you can achieve it by shutting down the ExecutorService that performs the async request.
For example I had this code to build the RestAdapter:
Builder restAdapter = new RestAdapter.Builder();
restAdapter.setEndpoint(BASE_URL);
restAdapter.setClient(okClient);
restAdapter.setErrorHandler(mErrorHandler);
mExecutorService = Executors.newCachedThreadPool();
restAdapter.setExecutors(mExecutor, new MainThreadExecutor());
restAdapter.setConverter(new GsonConverter(gb.create()));
and had this method for forcefully abandoning the requests:
public void stopAll(){
List<Runnable> pendingAndOngoing = mExecutorService.shutdownNow();
// probably await for termination.
}
Alternatively you could make use of ExecutorCompletionService and either poll(timeout, TimeUnit.MILISECONDS) or take() all ongoing tasks. This will prevent thread pool not being shut down, as it would do with shutdownNow() and so you could reuse your ExecutorService
Hope it would be of help for someone.
Edit: As of OkHttp 2 RC1 changelog performing a .cancel(Object tag) is possible. We should expect the same feature in upcoming Retrofit:
You can use actual Request object to cancel it
okClient.cancel(request);
or if you have supplied tag to Request.Builder you have to use
okClient.cancel(request.tag());
All ongoing, executed or pending requests are queued inside Dispatcher, okClient.getDispatcher(). You can call cancel method on this object too. Cancel method will notify OkHttp Engine to kill the connection to the host, if already established.
Edit 2: Retrofit 2 has fully featured canceling requests.
Wrap the callback in a delegate object that implements Callback as
well. Call some method to clear out the delegate and have it just
no-op whenever it gets a response.
Look at the following discussion
https://plus.google.com/107765816683139331166/posts/CBUQgzWzQjS
Better strategy would be canceling the callback execution
https://stackoverflow.com/a/23271559/1446469
I've implemented cancelable callback class based on answer https://stackoverflow.com/a/23271559/5227676
public abstract class CancelableCallback<T> implements Callback<T> {
private static List<CancelableCallback> mList = new ArrayList<>();
private boolean isCanceled = false;
private Object mTag = null;
public static void cancelAll() {
Iterator<CancelableCallback> iterator = mList.iterator();
while (iterator.hasNext()){
iterator.next().isCanceled = true;
iterator.remove();
}
}
public static void cancel(Object tag) {
if (tag != null) {
Iterator<CancelableCallback> iterator = mList.iterator();
CancelableCallback item;
while (iterator.hasNext()) {
item = iterator.next();
if (tag.equals(item.mTag)) {
item.isCanceled = true;
iterator.remove();
}
}
}
}
public CancelableCallback() {
mList.add(this);
}
public CancelableCallback(Object tag) {
mTag = tag;
mList.add(this);
}
public void cancel() {
isCanceled = true;
mList.remove(this);
}
#Override
public final void success(T t, Response response) {
if (!isCanceled)
onSuccess(t, response);
mList.remove(this);
}
#Override
public final void failure(RetrofitError error) {
if (!isCanceled)
onFailure(error);
mList.remove(this);
}
public abstract void onSuccess(T t, Response response);
public abstract void onFailure(RetrofitError error);
}
Usage example
rest.request(..., new CancelableCallback<MyResponse>(TAG) {
#Override
public void onSuccess(MyResponse myResponse, Response response) {
...
}
#Override
public void onFailure(RetrofitError error) {
...
}
});
// if u need to cancel all
CancelableCallback.cancelAll();
// or cancel by tag
CancelableCallback.cancel(TAG);
This is for retrofit 2.0, the method call.cancel() is there which cancels the in-flight call as well. below is the document definition for it.
retrofit2.Call
public abstract void cancel()
Cancel this call. An attempt will be made to cancel in-flight calls, and if the call has not yet been executed it never will be.
Now there is an easy way in latest version of Retrofit V 2.0.0.beta2. Can implement retry too.
Take a look here How to cancel ongoing request in retrofit when retrofit.client.UrlConnectionClient is used as client?
According to the Retrofit 2.0 beta 3 changelog via link https://github.com/square/retrofit/releases/tag/parent-2.0.0-beta3
New: isCanceled() method returns whether a Call has been canceled. Use this in onFailure to determine whether the callback was invoked from cancelation or actual transport failure.
This should make stuff easier.
I might be a bit late, but I've possibly found a solution.
I haven't been able to prevent a request from being executed, but if you're satisfied with the request being performed and not doing anything, you might check this question and answer, both made by me.