Я пытаюсь запустить две AsyncTasks одновременно. (Платформа Android 1.5, HTC Hero.) Однако выполняется только первое. Вот простой фрагмент, чтобы описать мою проблему:
public class AndroidJunk extends Activity {
class PrinterTask extends AsyncTask<String, Void, Void> {
protected Void doInBackground(String ... x) {
while (true) {
System.out.println(x[0]);
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new PrinterTask().execute("bar bar bar");
new PrinterTask().execute("foo foo foo");
System.out.println("onCreate() is done.");
}
}
Результат, который я ожидаю:
onCreate() is done.
bar bar bar
foo foo foo
bar bar bar
foo foo foo
И так далее. Однако, что я получаю, это:
onCreate() is done.
bar bar bar
bar bar bar
bar bar bar
Второй AsyncTask никогда не выполняется. Если я изменю порядок операторов execute (), только задача foo выдаст результат.
Я что-то упускаю здесь очевидное и / или делаю что-то глупое? Разве невозможно выполнить две AsyncTasks одновременно?
Редактировать: я понял, что телефон работает под управлением Android 1.5, я обновил описание проблемы. соответственно. У меня нет этой проблемы с HTC Hero под управлением Android 2.1. Хм ...
Ответы:
AsyncTask использует шаблон пула потоков для запуска вещи из doInBackground (). Изначально проблема заключалась в том, что в ранних версиях ОС Android размер пула составлял всего 1, что означает отсутствие параллельных вычислений для группы AsyncTasks. Но позже они исправили это, и теперь размер равен 5, поэтому максимум 5 AsyncTasks могут работать одновременно. К сожалению, я не помню, в какой версии именно они это изменили.
ОБНОВИТЬ:
Вот что говорит текущий API (2012-01-27) об этом:
DONUT - это Android 1.6, HONEYCOMB - это Android 3.0.
ОБНОВЛЕНИЕ: 2
Смотрите комментарий
kabuko
отMar 7 2012 at 1:27
.Оказывается, что для API, в которых используется «пул потоков, позволяющий нескольким задачам работать параллельно» (начиная с 1.6 и заканчивая 3.0), количество одновременно выполняемых AsyncTasks зависит от того, сколько задач уже передано для выполнения, но еще не закончили их
doInBackground()
.Это проверено / подтверждено мной на 2.2. Предположим, у вас есть пользовательский AsyncTask, который просто спит секунду
doInBackground()
. AsyncTasks использует очередь фиксированного размера для хранения отложенных задач. Размер очереди по умолчанию равен 10. Если вы запускаете 15 своих пользовательских задач подряд, то первые 5 будут вводить ихdoInBackground()
, а остальные будут ждать в очереди свободного рабочего потока. Как только любой из первых 5 завершается и, таким образом, освобождает рабочий поток, задача из очереди начнет выполнение. Таким образом, в этом случае не более 5 задач будут выполняться одновременно. Однако, если вы запустите 16 своих пользовательских задач подряд, то первые 5 войдут в ихdoInBackground()
, остальные 10 попадут в очередь, но 16-го будет создан новый рабочий поток, поэтому он сразу же начнет выполнение. Таким образом, в этом случае не более 6 задач будут выполняться одновременно.Существует ограничение на количество одновременно запускаемых задач. Поскольку
AsyncTask
используется исполнитель пула потоков с ограниченным максимальным числом рабочих потоков (128), а очередь отложенных задач имеет фиксированный размер 10, если вы попытаетесь выполнить более 138 своих пользовательских задач, приложение будет аварийно завершать работуjava.util.concurrent.RejectedExecutionException
.Начиная с версии 3.0, API позволяет использовать ваш собственный исполнитель пула потоков через
AsyncTask.executeOnExecutor(Executor exec, Params... params)
метод. Это позволяет, например, настроить размер очереди отложенных задач, если значение по умолчанию 10 не то, что вам нужно.Как упоминает @Knossos, есть возможность использовать
AsyncTaskCompat.executeParallel(task, params);
из библиотеки поддержки v.4 для параллельного запуска задач, не заботясь об уровне API. Этот метод устарел на уровне API 26.0.0.ОБНОВЛЕНИЕ: 3
Вот простое тестовое приложение для игры с множеством задач, параллельное и параллельное выполнение: https://github.com/vitkhudenko/test_asynctask
ОБНОВЛЕНИЕ: 4 (спасибо @penkzhou за указание на это)
Начиная с Android 4.4
AsyncTask
ведет себя иначе, чем было описано в разделе ОБНОВЛЕНИЕ: 2 . Существует исправление, предотвращающееAsyncTask
создание слишком большого количества потоков.До Android 4.4 (API 19)
AsyncTask
были следующие поля:В Android 4.4 (API 19) вышеуказанные поля изменены на:
Это изменение увеличивает размер очереди до 128 элементов и уменьшает максимальное количество потоков до количества ядер ЦП * 2 + 1. Приложения могут по-прежнему отправлять такое же количество задач.
источник
AsyncTaskCompat.executeParallel(task, params);
AsyncTaskCompat.executeParallel(task, params);
он устарелЭто позволяет выполнять параллельное выполнение на всех версиях Android с API 4+ (Android 1.6+):
Это краткое изложение превосходного ответа Архимеда.
Убедитесь, что вы используете API уровня 11 или выше в качестве цели сборки проекта. В Eclipse это так
Project > Properties > Android > Project Build Target
. Это не нарушит обратную совместимость с более низкими уровнями API. Не волнуйтесь, вы получите ошибки Lint, если вы случайно используете функции, представленные позжеminSdkVersion
. Если вы действительно хотите использовать функции, представленные позжеminSdkVersion
, вы можете устранить эти ошибки с помощью аннотаций, но в этом случае вам нужно позаботиться о совместимости самостоятельно . Это именно то, что произошло во фрагменте кода выше.источник
void startMyTask(AsyncTask<Void, ?, ?> asyncTask)
(если ваш doInBackground принимает Void)Сделать предложение @sulai более общим:
источник
Просто чтобы включить последнее обновление (ОБНОВЛЕНИЕ 4) в безупречный ответ @Arhimed в очень хорошее резюме @sulai:
источник
.executeOnExecutor()
что теперь избыточно для API> = KITKAT, да?Пример загрузки растровых изображений разработчиками Android эффективно использует пользовательскую асинхронную задачу (скопированную с jellybean), поэтому вы можете использовать executeOnExecutor с значением apis ниже <11
http://developer.android.com/training/displaying-bitmaps/index.html
Загрузите код и перейдите в пакет утилит.
источник
Это возможно. Версия моего Android-устройства 4.0.4 и android.os.Build.VERSION.SDK_INT - 15
У меня 3 блесны
А также у меня есть класс Async-Tack.
Вот мой код загрузки блесны
Это работает отлично. Один за другим загружены мои счетчики. Я не пользователь executeOnExecutor.
Вот мой класс Async-задачи
источник
если вы хотите выполнять задачи параллельно, вам нужно вызвать метод
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "your task name")
после Android версии 3.0; но этот метод не существует до Android 3.0 и после 1.6, потому что он выполняется параллельно сам по себе, поэтому я предлагаю вам настроить свой собственный класс AsyncTask в вашем проекте, чтобы избежать исключения исключения в другой версии Android.источник