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.
Related
Here is the thing. While in UI thread, I posted an async callback in the UI thread. Is it possible to wait for the callback and execute synchronously
A good example would be to wait for WebView's evaluateJavascript while in UI thread.
//In the UI thread
webView.evaluateJavascript("javascript:.....", callback)
//Needs to be sure that the callback is completed
dosomething()
I know it's recommended to put dosomething() inside the callback. But in certain circumstance, it is not safe, like performing actions in onPause(). If you don't wait synchronously, then the view can be destroyed at any time.
override fun onPause(){
webView.evaluateJavascript("javascript:.....", callback)
doNotContinueUntilCallbackCompletes()
super.onPause()
}
Since we are in the same thread as the callback, so CountDownLatch didn't work. It blocks the entire UI thread. And since we need to access webView, so we have to make the callback in the UI thread.
So what is the correct way to do this?
Not in the general case, no. For one thing, a callback is not necessarily asynchronous. A callback could occur on the same thread. In which case waiting for it would be instant deadlock of that thread. An example of a callback that is rarely asynchronous is a visitor pattern that walks an object hierarchy. Another would be a library that posts back to the main thread when done, like Volley.
Now if you assume the callback will be called asynchronusly, then you could use a Future to wait for it- or just signal a semaphore in your callback (which is more or less what a future would do).
However, you almost never want to do this, and NEVER from the UI thread. If you did it from the UI thread the entire app would freeze. That's why you do things on other threads. Waiting for it in that case would always be a mistake. If it wasn't from the UI thread there are some use cases for it (mainly when interacting with libraries that do their own threading), but if you're going to do work on another thread and get a callback- why not just do the work now on this thread?
Also, doing it in onPause like that would probably trip a watchdog timer and cause the entire app to crash uncleanly. Lifecycle functions have a limited time to run.
So, I am working with some code that performs seemingly asynchronous tasks and uses the typical callback/listener model to receive callbacks.
My problem is that sometimes the callbacks never fire if I hold up the thread that called the operation.
Considering the following snippet of code:
doAsync(new Callback(){
// Callback here
});
The internals of doAsync() are using a handler and the main looper.
Considering I call this code from Thread A can somebody please outline the effects of blocking the Thread A right after this call.
Also, what are the effects of running the Handler on main looper and local looper will it determine the thread that the above callback is executed on? I ask this because if I block Thread A then the callback never executes.
calling in Async Task does not block the main thread...doInBackground method executes the operations in background thread...if you want to update the UI after your execution in background has completed you must override the onPostExecute() method....there are some other hooks for UI thread too like onProgressUpdate and OnCancelled in AsyncTask....please check the java doc of AsyncTask for details
I am struggling with the some threading stuff in android.
The situation is, that I have a table, which is getting filled during ui actions of the user.
And this table is added to a queue. I chose LinkedBlockingQueue until now.
(Please correct me if this is a bad Idea).
At the same time there is a background-thread, that should fetch (read) the queue and prepare another table, which itself then is passed to a method, which should be invoked on the UI thread.
(Meaning, the background-thread only collects the queued table in background in order to pass them to another method later on ).
So I read about the various approaches to do this in some ways and found myself in the AsyncTask.
But AsyncTask only allows me pre execution or post execution as options to invoke methods/code in the UI thread.
I want to decide myself, when I invoke some methods on the UI thread , because the background-thread still has to do some work after he invoked the method in UI thread.
Ah, as information: The background-thread never stops unless the user exits the application or a special idle timeout occurred.
And : Invoking the mentioned method on UI thread will also be parametrized.
But async task only allows me pre execution or post execution as options to invoke methods/code in the ui thread.
No. onProgressUpdate() also runs on the UI Thread. You run this function by calling publishProgress() in doInBackground() when the UI needs to be update while background operations are still running.
Here is an answer with an example of using it
publishProgress() Docs
Make sure to read through the AsyncTask Docs thoroughly several times. They are a bit tricky at first until you get it.
I recently looked through SO to find the answer to the same question here, but there was not an answer directed at the question in regards to the risk of doing so. But basically I want to run another AsyncTask inside the doInBackground() method of another AsyncTask. Is this a bad approach and/or does it leave any potential side effects?
I know that running it in the onPostExecute() works and so far from past experiences I have not had any issues due to the fact that onPostExecute() runs back on the main thread which started a AsyncTask to begin with.
From the API docs:
•The task instance must be created on the UI thread.
doInBackground() runs on the background thread. So you cannot create and run another asynctask from doInBackground().
http://developer.android.com/reference/android/os/AsyncTask. Have a look at the topic under threading rules.
When an asynchronous task is executed, the task goes through 4 steps: (Straight from the doc)
1.onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
2.doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
3.onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
4.onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
If you truly want parallel execution, you can invoke executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR.
Also you can consider using an alternative RoboSpice.https://github.com/octo-online/robospice.
Can make multiple spice request. Notitifes on the ui thread when task is complete. Worth having a look at robospice.
AsyncTask(), with the exception of the Honeycomb releases, execute serially. So, no, you cannot execute another AsyncTask() from within doInBackground() -- I guess I should say that I've never tried it, but it's highly unlikely you're going to achieve the desired affect.
I asked about AsyncTask() execution during one of the Google Office Hours. Straight from their mouths when asked, "Why did it change from serial to parallel and back to serial execution?"; "Because it broke a lot of stuff."
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.