Ответ 1
Примечание. Вся информация, приведенная ниже, доступна на странице разработчиков Android AsyncTask. В этом примере заголовок Использование. Также взгляните на запись в блоге разработчиков Android безболезненного потока.
Посмотрите исходный код для AsynTask.
Смешная нотация < >
позволяет настроить задачу Async. Скобки используются для поддержки generics в Java.
Есть 3 важные части задачи, которую вы можете настроить:
- Тип переданных параметров - любое число, которое вы хотите
- Тип того, что вы используете для обновления индикатора выполнения/индикатора
- Тип для того, что вы возвращаете после выполнения фоновой задачи
И помните, что любой из вышеперечисленных может быть интерфейсами. Так вы можете передавать несколько типов по одному и тому же вызову!
Вы помещаете типы этих трех вещей в угловые скобки:
<Params, Progress, Result>
Итак, если вы собираетесь пройти через URL
и использовать Integers
для обновления прогресса и возврата логического успеха, который вы хотите записать:
public MyClass extends AsyncTask<URL, Integer, Boolean> {
В этом случае, если вы загружаете растровые изображения, например, вы будете обрабатывать то, что вы делаете с растровыми изображениями в фоновом режиме. Вы также можете просто вернуть HashMap Bitmaps, если хотите. Также помните, что переменные-члены, которые вы используете, не ограничены, поэтому не чувствуйте себя слишком привязанными параметрами, прогрессом и результатом.
Чтобы запустить экземпляр AsyncTask, а затем execute
он либо последовательно, либо параллельно. В ходе выполнения вы передаете переменные. Вы можете перейти более чем к одному.
Обратите внимание, что вы не вызываете doInBackground()
напрямую. Это связано с тем, что это приведет к нарушению магии AsyncTask, которая заключается в том, что doInBackground()
выполняется в фоновом потоке. Вызов его напрямую, как есть, заставит его работать в потоке пользовательского интерфейса. Итак, вместо этого вы должны использовать форму execute()
. Задачей execute()
является запуск doInBackground()
в фоновом потоке, а не в потоке пользовательского интерфейса.
Работа с нашим примером сверху.
...
myBgTask = new MyClass();
myBgTask.execute(url1, url2, url3, url4);
...
onPostExecute
будет срабатывать, когда будут выполнены все выполняемые задачи.
myBgTask1 = new MyClass().execute(url1, url2);
myBgTask2 = new MyClass().execute(urlThis, urlThat);
Обратите внимание, как вы можете передать несколько параметров на execute()
, который передает несколько параметров на doInBackground()
. Это достигается с помощью varargs (вы знаете, как String.format(...)
. Многие примеры показывают только извлечение первого params с помощью params[0]
, но вы должны убедиться, что вы получили все параметры. Если вы передаете URL-адреса это было бы (взято из примера AsynTask, есть несколько способов сделать это):
// This method is not called directly.
// It is fired through the use of execute()
// It returns the third type in the brackets <...>
// and it is passed the first type in the brackets <...>
// and it can use the second type in the brackets <...> to track progress
protected Long doInBackground(URL... urls)
{
int count = urls.length;
long totalSize = 0;
// This will download stuff from each URL passed in
for (int i = 0; i < count; i++)
{
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
// This will return once when all the URLs for this AsyncTask instance
// have been downloaded
return totalSize;
}
Если вы собираетесь выполнять несколько задач bg, вы должны учесть, что вышеуказанные вызовы myBgTask1
и myBgTask2
будут выполняться последовательно. Это здорово, если один вызов зависит от другого, но если вызовы независимы - например, вы загружаете несколько изображений, и вам все равно, какие из них поступают первыми, - тогда вы можете совершать вызовы myBgTask1
и myBgTask2
параллельно с THREAD_POOL_EXECUTOR
:
myBgTask1 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url1, url2);
myBgTask2 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urlThis, urlThat);
Примечание:
Пример
Вот пример AsyncTask, который может принимать столько же типов, сколько требуется для одной и той же команды execute()
. Ограничение состоит в том, что каждый тип должен реализовывать один и тот же интерфейс:
public class BackgroundTask extends AsyncTask<BackgroundTodo, Void, Void>
{
public static interface BackgroundTodo
{
public void run();
}
@Override
protected Void doInBackground(BackgroundTodo... todos)
{
for (BackgroundTodo backgroundTodo : todos)
{
backgroundTodo.run();
// This logging is just for fun, to see that they really are different types
Log.d("BG_TASKS", "Bg task done on type: " + backgroundTodo.getClass().toString());
}
return null;
}
}
Теперь вы можете сделать:
new BackgroundTask().execute(this1, that1, other1);
Где каждый из этих объектов - другой тип! (который реализует один и тот же интерфейс)