Reputation: 6094
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.
Upvotes: 20
Views: 9071
Reputation: 7123
You can use it in your AutoCompleteTextView's adapter's filter.
private class Adapter extends BaseAdapter implements Filterable{
getFilter(){
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
List<String> suggestions = MyApiSuggestionsApi(constraint).get();
return packageAsFilterResults(suggestions);
}
}
}
Upvotes: 0
Reputation: 2507
I have an application to edit photos, the user is capable of opening photos from URLs.
I used an AsyncTask to download the photo from the URL, during this time the UI should be blocked. what i did is I showed a ProgressBar starts the AsyncTask's get() method than hide the ProgressBar..
It seemed the best and simplest solution for me.
Upvotes: -1
Reputation: 7082
It appears as though AsyncTask.get() blocks the caller thread, where AsyncTask.execute() does not.
You might want to use AsyncTask.get() for test cases where you want to test a particular Web Service call, but you do not need it to be asynchronous and you would like to control how long it takes to complete. Or any time you would like to test against your web service in a test suite.
Syntax is the same as execute:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
new DownloadFilesTask().get(5000, TimeUnit.MILLISECONDS);
Upvotes: 2
Reputation: 7846
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:
AsyncTask
s 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.AsyncTask
, it places the AsyncTask
object in a queue, for additional processing by a separate background thread once the results are available.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.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 AsyncTask
s. 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 :-).
Upvotes: 18
Reputation: 157457
As the documentaion stands:
"Waits if necessary for the computation to complete, and then retrieves its result."
So it is mandatory that you avoid to call it on the UI Thread, otherwise you will get the NetworkOnMainThreadException
. I would use it in a test enviroment which involves net operations or to wait another task to finish.
EDIT: I was wrong about NetworkOnMainThreadException
.
Upvotes: 2
Reputation: 6094
I post my own answer, as it is what I think at this moment and nobody has given it.
My curiosity is still alive, so I wont mark this one as correct. If someone answers this question brilliantly, I will mark his/her answer as correct.
My answer is that there is actually no scenario where using the AsyncTask's get()
method is the best solution.
IMHO, using this method is pointless. What I mean is that there always seem to be a better solution.
Likewise, I would say it's semantically shocking, as calling it changes your AsyncTask into an effective "SyncTask".
Upvotes: 3
Reputation: 1994
I usually use the handler class to do the trick (Loading media async). Like:
public void setRightSongAdele(Song current)
{
RetriveCorrelateGenreSong rcgs = new RetriveCorrelateGenreSong(current);
new Thread(rcgs).start();
}
@SuppressLint("HandlerLeak")
Handler updateRightAdeleHandler = new Handler()
{
@Override
public void handleMessage(Message msg) {
songNextText.setText(utils.reduceStringLength(rightSong.getTitle(), 15));
adeleNext.setImageBitmap(utils.getAlbumArtFromSong(rightSong.getPath(), getApplicationContext()));
}
};
Upvotes: 4
Reputation: 115952
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.
Upvotes: 5
Reputation: 4354
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.
Upvotes: 5