Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AsyncTask's get() method: Is there any scenario where it is actually the best option?

After answering this question, I got a doubt about the sense/usefulness of using the get() method of Android's AsyncTask class.

public final Result get ()

Waits if necessary for the computation to complete, and then retrieves its result. 

Basically, a synchronous solution to the AsyncTask class, that blocks (freezes) the UI until the background operations are finished.

Other than test purposes, and even in those cases, I can't really think in any scenario where it is actually a good solution, but I may be wrong, so I feel curious.

If you need the user to actually wait until the AsyncTask finishes, you can show a Dialog or ProgressDialog, having the control of the UI in every moment. I know it's not exactly the same, but IMHO it's a much better approach than using the get() method.

like image 970
Alejandro Colorado Avatar asked Jun 04 '13 08:06

Alejandro Colorado


People also ask

What happens if we call execute () more than once in async task?

What happens if we call Execute () more than once in async task? if we execute more than one AsyncTask at a time, they will run sequentially by the default version from Android 3.0 onwards.

What method must be overridden for using AsyncTask?

AsyncTask must be subclassed to be used. The subclass will override at least one method ( doInBackground(Params...) ), and most often will override a second one ( onPostExecute(Result) .)

What can I use instead of AsyncTask?

AsyncTask is used to perform time talking operations in android, but it's marked as deprecated from android 11. There are many alternatives are available for replacing an AsyncTask, one of the replacements is ExecutorService.

How many times an instance of AsyncTask can be executed?

AsyncTask instances can only be used one time.


3 Answers

AsyncTask isn't the only way of doing background operations. Indeed, the documentation says that AsyncTask should only be used for operations take at most a few seconds. So if you've got tasks that take longer, they should be coded via classes that implement the runnable interface. Such tasks in other (non AsyncTask) threads may well want to wait for an AsyncTask to finish, so it seems to me that the idea that there are no situations where one would want to use AsyncTask.get() is false.

Update: In response to a comment, to emphasize that this could be a valid use of AsyncTask.get(), the following is possible:

  • There could be AsyncTasks that get initiated from the UI thread, which might involve communicating over the internet, e.g. loading a web page, or communicating with a server. Whatever the results of the AsyncTask are, some (or all) of the results are needed to update the screen. Hence an AsyncTask with its doInBackground followed by onPostExecute on the UI thread makes sense.
  • Whenever the UI thread initiates an AsyncTask, it places the AsyncTask object in a queue, for additional processing by a separate background thread once the results are available.
  • For each AsyncTask in the queue in turn, the background thread uses AsyncTask.get() to wait for the task to finish, before doing the additional processing. One obvious example of additional processing could simply be logging all such AsyncTask activities to a server on the internet, so it makes sense to do this in the background.
The following code shows what I mean. The app calls KickOffAsynctask(...) whenever it wants to do an AsyncTask, and there's a background thread that will automatically pickup the task for post-processing once the task is complete.
public class MyActivity extends Activity {

    static class MyAsyncTaskParameters { }
    static class MyAsyncTaskResults { }

    Queue<MyAsyncTask> queue;   // task queue for post-processing of AsyncTasks in the background
    BackgroundThread b_thread;  // class related to the background thread that does the post-processing of AsyncTasks

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);     
        queue = new  ConcurrentLinkedQueue<MyAsyncTask>();
        b_thread = new BackgroundThread(queue);
        b_thread.Start();       
    }

    void KickOffAsynctask(MyAsyncTaskParameters params) {
        MyAsyncTask newtask = new MyAsyncTask();
        newtask.execute(params);
        synchronized(queue) {
            queue.add(newtask);
        }
    }

    static class MyAsyncTask extends AsyncTask<MyAsyncTaskParameters, Void, MyAsyncTaskResults> {

        @Override
        protected MyAsyncTaskResults doInBackground(MyAsyncTaskParameters... params) {
            MyAsyncTaskResults results = new MyAsyncTaskResults();
            // do AsyncTask in background
            return results;
        }

        @Override
        protected void onPostExecute(MyAsyncTaskResults res){
            // take required results from MyAsyncResults for use in the user interface
        }

    }

    static class BackgroundThread implements Runnable {
        // class that controls the post processing of AsyncTask results in background

        private Queue<MyAsyncTask> queue;
        private Thread thisthread;
        public boolean continue_running;

        public BackgroundThread(Queue<MyAsyncTask> queue) {
            this.queue=queue; thisthread = null; continue_running = true;
        }

        public void Start() {
            thisthread = new Thread(this);
            thisthread.start();
        }

        @Override
        public void run() {
            try {
                do {
                    MyAsyncTask task;
                    synchronized(queue) {
                        task = queue.poll();
                    }
                    if (task == null) {
                        Thread.sleep(100);
                    } else {
                        MyAsyncTaskResults results = task.get();
                        // post processing of AsyncTask results in background, e.g. log to a server somewhere
                    }
                } while (continue_running);     
            } catch(Throwable e) {
                e.printStackTrace();
            }           
        }

    }

}

Update2. Another possible valid use of AsyncTask.get() has occurred to me. The standard advice is not to use AsyncTask.get() from the UI thread, because it causes the user interface to freeze until the result is available. However, for an app where stealth is needed, that may be exactly what is required. So how about the following situation: James Bond breaks into the hotel room of Le Chiffre and only has a couple of minutes to extract all the data from the villian's phone and install the monitoring virus. He installs the app provided by Q and starts it running, but he hears someone coming so he has to hide. Le Chiffre enters the room and picks up his phone to make a call. For a few seconds the phone seems a bit unresponsive, but suddenly the phone wakes up and he makes his phone call without further thought. Of course, the reason for the unresponsiveness was the fact that Q's app was running. It had various tasks to do, and some of them needed to be done in a particular order. The app used two threads to do the work, namely the UI thread itself and the single background thread that processes AsyncTasks. The UI thread was in overall control of all the tasks, but because some tasks needed to be done before other tasks, there were points in the app where the UI thread used AsyncTask.get() while waiting for the background task to finish :-).

like image 104
Stochastically Avatar answered Oct 28 '22 23:10

Stochastically


The get method should never be used in the UI thread because it will (as you noticed) freeze your UI. It should be used in a background thread to wait for the end of your task, but generally speaking, try to avoid AsyncTask as much as possible (WHY?).

I would suggest a callback or eventbus as a replacement.

like image 23
AMerle Avatar answered Oct 29 '22 00:10

AMerle


if you run multiple asyncTasks in parallel , you might want that some tasks would wait for the result of others.

however, i think you should avoid running too many asyncTasks in parallel, because it will slow down the device.

like image 43
android developer Avatar answered Oct 28 '22 22:10

android developer