I would like to handle a return result from an AsyncTask outside of the class.
Is there any downside using, for example, Location loc = TheClass.execute().get();? Should I handle the result in onPostExecute inside the class instead?
The get() method is not well method for it, cause it stoped UI-thread
The only place where you can be assured that the operation you have started in doInBackground() has completed is the callback method onPostExecute(). So using a get() is not such a wise idea as far as AsyncTask is concerned.
get()
The purpose, of get(), is to block until the result is obtained. This
could be useful, for example, if you have multiple tasks, where one uses
another. One task could start another and call get() to wait for it to
finish before continuing with its own work.
onPostExecute (Result result)
Runs on the UI thread after doInBackground(Params...). The specified result is the value returned by doInBackground(Params...).
This method won't be invoked if the task was cancelled.
get() make you (current Thread) wait until the result come and onPostExecute did work Asynchronously and work like a call back when the background work has been completed.
http://developer.android.com/reference/android/os/AsyncTask.html#get()
public final Result get ()
Waits if necessary for the computation to complete, and then retrieves its result.
Related
I have an object Task (see com.google.android.gms.tasks)
I need to wait till It has finished all operations before return result.
So I have tried to create a dummy object
final static Object lock=new Object();
to use as lock and I have added in the method
synchronized(lock){
lock.wait();
}
so that It doesn't return the value before task completion
calling lock.notifyAll in onSuccess() listener of the task (this listener is called when the task ends correctly).
But unfortunately the whole App freeze.
Why happens this?
How should I deal with Task completion?
(Note that Task isn't like AsyncTask)
There is a simple way to run a Task synchronously.
Tasks.await(yourTask);
But make sure this is called in a background thread.
This question already has answers here:
Ideal way to cancel an executing AsyncTask
(9 answers)
Closed 5 years ago.
I have a class name is GetData that extends from AsyncTask. In other class I have an object from GetData and with this codes I use that:
GetData getData = new GetData();
getData().execute();
I want to stop this thread when a button clicked. I do this with:
getData().cancel(true);
I want to know if I canceled thread while it is in doInBackground, it stopped or it goes to onPostExecute and then stop?
A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)
For further details visit:
https://developer.android.com/reference/android/os/AsyncTask.html
Just like:
onPostExecute(Result result)
{
}
you can override a method for cancel to update your UI accordingly when your asyncTask is cancelled as follows:
onCancelled(Result result)
{
// here you can handle situation according to your requirements
}
So point of your interest here is that whenever you cancel your task before it enters into onPostExecute it will not go into onPostExecute but will jump to onCancelled. You can also call task.cancel(true); in postExecute according to your condition by applying required checks.
From the Android documentation:
Calling this method will result in onCancelled(Object) being invoked on the UI thread after doInBackground(Object[]) returns. Calling this method guarantees that onPostExecute(Object) is never invoked.
So onPostExecute will not be called.
I've noticed on the documentation for AsyncTask here that you can use a method called get() to retrieve your result once the work on the thread is done. The documentation says that it
Waits if necessary for the computation to complete, and then retrieves its result.
Does that mean if I have this line of code:
List<Data> data = someAsyncTask.execute.get();
in the main UI thread, does it wait for the task to complete before executing any code after it? If so, this would render the use of AsyncTask useless. What am I missing here?
Is AsyntTask.get() an alternative to using onPostExecute() to return data to the main thread? If so, is it safe? Or is its use for something completely different?
If you call AsyncTask.get() and the task is not completed, then current thread will wait (and can be interrupted).
You right, calling this method in UI thread makes AsyncTask useless. But you can call it in another thread which need result of this task for further execution.
Ho do i get my function to wait for being done with it's async task before returning the variable?
public boolean CheckOnline(){
OnlineAsyncTask onlinetsk = new OnlineAsyncTask();
onlinetsk.execute();
return Online;
}
You can call get() to wait for the async task to complete and retrieve the result.
However that defeats the purpose of an async task - it's no longer asynchronous. Consider redesigning your app so that you don't need to wait for a result. Instead e.g. use a callback interface to notify that the async task has finished and a result is available.
String str_result= new OnlineAsyncTask().execute().get();
This will make it wait till it returns the value
I am currently hunting a nasty bug in a multi-threaded environment using FutureTasks and Executors. The basic idea is this to have a fixed number of threads execute individual FutureTasks that compute a result that is to be displayed in a a table (never mind the GUI aspect here).
I have been looking at this for so long, I am beginning to doubt my sanity.
Consider this piece of code:
public class MyTask extends FutureTask<Result> {
private String cellId;
...
protected void done() {
if (isCancelled()) return;
try {
Result r = get(); // should not wait, because we are done
... // some processing with r
sendMessage(cellId, r);
} catch (ExecutionException e) { // thrown from get
...
} catch (InterruptedException e) { // thrown from get
...
}
}
...
}
When done() is called by an Executor handling an instance of MyTask, I check if I got there, because the task was cancelled. If so, I skip all remaining activities, especially I do not call sendMessage().
The documentation for FutureTask.done() says:
Protected method invoked when this task transitions to state isDone (whether normally or via cancellation). The default implementation does nothing. Subclasses may override this method to invoke completion callbacks or perform bookkeeping. Note that you can query status inside the implementation of this method to determine whether this task has been cancelled.
(API Reference)
But what I do not get from the documentation of FutureTask are the semantics while done() is being executed. What if I pass the isCancelled() check at the beginning, but right after that some other thread calls my cancel() method? Will that cause my task to change its mind and reply isCancelled() == true from then on?
If so, how would I later know if the the message was sent? Looking at isDone() would just tell me that execution of the task was finished, but as isCancelled() were true then as well, I could not know if it got to send the message out in time.
Maybe this is obvious, but I do not really see it right now.
FutureTask#done() is called no more than once for any given instance, and it's only called for one reason -- run() completed either with or without error, or cancel() ran before either of the preceding events occurred. The record of completion by any of these outcomes is latching. The reason a FutureTask completed can't change, regardless of competing events seemingly happening "at the same time."
Hence, within FutureTask#done() only one of isCancelled() or isDone() will return true then and forever more. It's difficult to distinguish between isDone() reporting true by way of error or successful completion. You can't override set() or setException(Throwable) decisively, as both delegate to the inner AQS to decide whether the attempt to record a successful yielding of a value or encountering an exception should stick. Overriding either method only lets you know that it was called, but you can't observe the decision made by the base implementation. If either event occurs "too late"—say, after cancellation—the attempt to record the value or the exception will be ignored.
Studying the implementation, the only way I see to discern a non-canceled successful outcome from an error is to bite the bullet and call get().
From the API (emphasis mine):
public boolean cancel(boolean mayInterruptIfRunning)
Description copied from interface: Future
Attempts to cancel execution of this task. This attempt will fail if the task has already completed, already been cancelled, or could not be cancelled for some other reason.
So FutureTask is working off the assumption that you cannot cancel a task when it has transitioned to the isDone stage.
Why not send the message "outside" of the task, based on the outcome of the Future<V> object returned by an ExecutorService? I've used this pattern and it seems to work well: Submit a bunch of Callable<V> tasks through an ExecutorService. Then, for each primary task, submit a secondary task that waits on the Future<V> of the primary task and does some follow-up action (like send a message) only if the Future<V> indicates that the primary task completed successfully. There is no guesswork with this approach. When the call to Future<V>.get() returns, you're guaranteed that the task has reached a terminal state, as long as you don't call the version of get that takes a timeout argument.
If you take this approach, you should use two separate ExecutorService instances: one for the primary tasks and one for the secondary ones. This is to prevent deadlocks. You don't want secondary tasks to start up and potentially block primary tasks from starting when the thread pool size is limited.
There's no need to extend FutureTask<V> at all. Just implement your tasks as Callable<V> objects. But if for some reason you want to detect if the task was canceled from within the Callable<V> code, just check the interrupt status of the thread with Thread.interrupted().
I suggest to write a small test case which allows you to call cancel() while your Future instance hangs in done() and see what happens.