Ответ 1
AsyncTask
- не единственный способ делать фоновые операции. В самом деле, в документации говорится, что AsyncTask
следует использовать только для выполнения операций не более нескольких секунд. Поэтому, если у вас есть задачи, которые занимают больше времени, они должны быть закодированы через классы, которые реализуют runnable interface. Такие задачи в других (не AsyncTask) потоках вполне могут подождать завершения AsyncTask
, поэтому мне кажется, что идея о том, что нет ситуаций, в которых вы хотели бы использовать AsyncTask.get()
, была ложной.
Обновление: В ответ на комментарий, чтобы подчеркнуть, что это может быть допустимым использованием AsyncTask.get()
, возможно следующее:
- Может быть
AsyncTask
, что инициировать из потока пользовательского интерфейса, который может включать обмен через Интернет, например загрузку веб-страницы или связь с сервером. Независимо от результатовAsyncTask
, некоторые (или все) результаты необходимы для обновления экрана. Следовательно,AsyncTask
с егоdoInBackground
, за которым следуетonPostExecute
в потоке пользовательского интерфейса, имеет смысл. - Всякий раз, когда поток пользовательского интерфейса инициирует
AsyncTask
, он помещает объектAsyncTask
в очередь, для дополнительной обработки отдельным фоновым потоком после получения результатов. - Для каждого
AsyncTask
в очереди, в свою очередь, фоновый поток используетAsyncTask.get()
для ожидания завершения задачи, прежде чем выполнять дополнительная обработка. Один очевидный пример дополнительной обработки может просто регистрировать все такие действияAsyncTask
на сервере в Интернете, поэтому имеет смысл сделать это в фоновом режиме.
KickOffAsynctask(...)
всякий раз, когда хочет сделать AsyncTask, и есть фоновый поток, который автоматически выполнит задачу для последующей обработки после завершения задачи.
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. Другое возможное использование AsyncTask.get()
произошло со мной. Стандартный совет - не использовать AsyncTask.get()
из потока пользовательского интерфейса, поскольку он заставляет пользовательский интерфейс зависеть, пока результат не будет доступен. Однако для приложения, где требуется скрытность, это может быть именно то, что требуется. Итак, как насчет следующей ситуации: Джеймс Бонд прорывается в гостиничный номер Le Chiffre и имеет только пару минут, чтобы извлечь все данные со звонкого телефона и установить вирус мониторинга. Он устанавливает приложение Q и запускает его, но он слышит, как кто-то идет, поэтому ему нужно скрыться. Le Chiffre входит в комнату и берет трубку, чтобы позвонить. На несколько секунд телефон кажется немного невосприимчивым, но вдруг телефон просыпается, и он делает свой телефонный звонок без дальнейших размышлений. Разумеется, причиной невнимательности было то, что приложение Q запущено. Ему приходилось выполнять различные задачи, и некоторые из них должны выполняться в определенном порядке. Приложение использовало два потока для выполнения работы, а именно сам пользовательский интерфейс и единственный фоновый поток, который обрабатывает AsyncTask
s. Поток пользовательского интерфейса полностью контролировал все задачи, но поскольку некоторые задачи нужно было выполнять перед другими задачами, в приложении присутствовали точки, в которых поток пользовательского интерфейса использовал AsyncTask.get()
, ожидая завершения фоновой задачи:-).