Android
AsyncTask
Поиск…
параметры
параметр | подробности |
---|---|
Params | тип параметров, отправленных в задачу при выполнении. |
Прогресс | тип единиц прогресса, опубликованных во время фоновых вычислений |
Результат | тип результата фонового вычисления. |
Основное использование
В действиях и службах Android большинство обратных вызовов запускаются в основном потоке . Это упрощает обновление пользовательского интерфейса, но выполнение основных задач с процессором или I / O в основном потоке может привести к тому, что ваш пользовательский интерфейс приостановится и перестанет отвечать ( официальная документация о том, что происходит).
Вы можете исправить это, поставив эти более тяжелые задачи на фоновый поток.
Один из способов сделать это - использовать AsyncTask , который обеспечивает основу для облегчения использования фонового потока, а также выполнения задач потока пользовательского интерфейса до, во время и после того, как фоновый поток завершил свою работу.
Методы, которые можно переопределить при расширении AsyncTask
:
-
onPreExecute()
: вызывается в потоке пользовательского интерфейса перед выполнением задачи -
doInBackground()
: вызывается в фоновом потоке сразу после того, какonPreExecute()
завершает выполнение. -
onProgressUpdate()
: вызывается в потоке пользовательского интерфейса после вызоваpublishProgress(Progress...)
. -
onPostExecute()
: вызывается в потоке пользовательского интерфейса после завершения фоновых вычислений
пример
public class MyCustomAsyncTask extends AsyncTask<File, Void, String> {
@Override
protected void onPreExecute(){
// This runs on the UI thread before the background thread executes.
super.onPreExecute();
// Do pre-thread tasks such as initializing variables.
Log.v("myBackgroundTask", "Starting Background Task");
}
@Override
protected String doInBackground(File... params) {
// Disk-intensive work. This runs on a background thread.
// Search through a file for the first line that contains "Hello", and return
// that line.
try (Scanner scanner = new Scanner(params[0])) {
while (scanner.hasNextLine()) {
final String line = scanner.nextLine();
publishProgress(); // tell the UI thread we made progress
if (line.contains("Hello")) {
return line;
}
}
return null;
}
}
@Override
protected void onProgressUpdate(Void...p) {
// Runs on the UI thread after publishProgress is invoked
Log.v("Read another line!")
}
@Override
protected void onPostExecute(String s) {
// This runs on the UI thread after complete execution of the doInBackground() method
// This function receives result(String s) returned from the doInBackground() method.
// Update UI with the found string.
TextView view = (TextView) findViewById(R.id.found_string);
if (s != null) {
view.setText(s);
} else {
view.setText("Match not found.");
}
}
}
Использование:
MyCustomAsyncTask asyncTask = new MyCustomAsyncTask<File, Void, String>();
// Run the task with a user supplied filename.
asyncTask.execute(userSuppliedFilename);
или просто:
new MyCustomAsyncTask().execute(userSuppliedFilename);
Заметка
При определении AsyncTask
мы можем передавать три типа между скобками < >
.
Определяется как <Params, Progress, Result>
(см. Раздел «Параметры» )
В предыдущем примере мы использовали типы <File, Void, String>
:
AsyncTask<File, Void, String>
// Params has type File
// Progress has unused type
// Result has type String
Void
используется, если вы хотите пометить тип как неиспользуемый.
Обратите внимание, что вы не можете передавать примитивные типы (т. int
, float
и еще 6 других) в качестве параметров. В таких случаях вы должны передать свои классы-оболочки , например Integer
вместо int
, или Float
вместо float
.
Жизненный цикл AsyncTask и Activity
AsyncTasks не соответствуют жизненному циклу экземпляров действий. Если вы запустите AsyncTask внутри Activity и вы повернете устройство, действие будет уничтожено, и будет создан новый экземпляр. Но AsyncTask не умрет. Он будет продолжаться до тех пор, пока он не завершится.
Решение: AsyncTaskLoader
Одним из подклассов Loaders является AsyncTaskLoader. Этот класс выполняет ту же функцию, что и AsyncTask, но намного лучше. Он легче справляется с изменениями конфигурации деятельности и ведет себя в жизненных циклах фрагментов и действий. Приятно, что AsyncTaskLoader можно использовать в любой ситуации, в которой используется AsyncTask. В любое время данные должны загружаться в память для Activity / Fragment для обработки, AsyncTaskLoader может выполнять работу лучше.
Отмена AsyncTask
YourAsyncTask task = new YourAsyncTask();
task.execute();
task.cancel();
Это не остановит вашу задачу, если она была в процессе, она просто устанавливает отмененный флаг, который можно проверить, проверив возвращаемое значение isCancelled()
(если ваш код запущен в данный момент), выполнив следующие действия:
class YourAsyncTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
while(!isCancelled()) {
... doing long task stuff
//Do something, you need, upload part of file, for example
if (isCancelled()) {
return null; // Task was detected as canceled
}
if (yourTaskCompleted) {
return null;
}
}
}
}
Заметка
Если AsyncTask отменяется, а doInBackground(Params... params)
все еще выполняется, тогда метод onPostExecute(Result result)
НЕ будет вызываться после doInBackground(Params... params)
. AsyncTask вместо этого вызовет onCancelled(Result result)
чтобы указать, что задача была отменена во время выполнения.
Успех публикации
Иногда нам необходимо обновить ход вычислений, выполненный с помощью AsyncTask
. Этот прогресс может быть представлен строкой, целым числом и т. Д. Для этого мы должны использовать две функции. Во-первых, нам нужно установить функцию onProgressUpdate
, тип параметра которой совпадает с параметром второго типа нашей AsyncTask
.
class YourAsyncTask extends AsyncTask<URL, Integer, Long> {
@Override
protected void onProgressUpdate(Integer... args) {
setProgressPercent(args[0])
}
}
Во-вторых, мы должны использовать функцию publishProgress
обязательно doInBackground
функции doInBackground
, и это все, предыдущий метод выполнит всю работу.
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;
}
Загрузить изображение с помощью AsyncTask в Android
В этом руководстве объясняется, как загрузить изображение с помощью AsyncTask в Android. Пример ниже загружает изображение, пока отображается индикатор выполнения во время загрузки.
Понимание Android AsyncTask
Задача Async позволяет реализовать MultiThreading, не втирая руки в потоки. AsyncTask обеспечивает правильное и простое использование потока пользовательского интерфейса. Он позволяет выполнять фоновые операции и передавать результаты в потоке пользовательского интерфейса. Если вы делаете что-то изолированное, связанное с пользовательским интерфейсом, например, загружая данные в список в списке, используйте AsyncTask.- AsyncTasks идеально подходит для коротких операций (максимум на несколько секунд).
- Асинхронная задача определяется тремя универсальными типами, называемыми Params, Progress и Result, и 4 шагами, называемыми
onPreExecute()
,doInBackground()
,onProgressUpdate()
иonPostExecute()
. - В
onPreExecute()
вы можете определить код, который должен быть выполнен до начала фоновой обработки. - doInBackground имеет код, который необходимо выполнить в фоновом режиме, здесь, в
doInBackground()
мы можем отправить результаты несколько раз в поток событий методом publishProgress (), чтобы уведомить об обработке фона, мы можем просто вернуть результаты. -
onProgressUpdate()
получает обновления прогресса отdoInBackground()
, который публикуется методомpublishProgress()
, и этот метод может использовать это обновление для обновления потока событий -
onPostExecute()
обрабатывает результаты, возвращаемые методомdoInBackground()
. - Используемые общие типы
- Парамс, тип параметров, отправленных в задачу при выполнении
- Прогресс, тип единиц прогресса, опубликованных во время фоновых вычислений.
- Результат, тип результата фонового вычисления.
- Если задача async не использует какие-либо типы, тогда ее можно пометить как тип Void.
- Запущенную задачу async можно отменить, вызвав метод
cancel(boolean)
.
Загрузка изображения с помощью Android AsyncTask
ваш макет .xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/downloadButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click Here to Download" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="Your image will appear here" />
</LinearLayout>
класс .java
package com.javatechig.droid;
import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class ImageDownladerActivity extends Activity {
private ImageView downloadedImg;
private ProgressDialog simpleWaitDialog;
private String downloadUrl = "http://www.9ori.com/store/media/images/8ab579a656.jpg";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.asynch);
Button imageDownloaderBtn = (Button) findViewById(R.id.downloadButton);
downloadedImg = (ImageView) findViewById(R.id.imageView);
imageDownloaderBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new ImageDownloader().execute(downloadUrl);
}
});
}
private class ImageDownloader extends AsyncTask {
@Override
protected Bitmap doInBackground(String... param) {
// TODO Auto-generated method stub
return downloadBitmap(param[0]);
}
@Override
protected void onPreExecute() {
Log.i("Async-Example", "onPreExecute Called");
simpleWaitDialog = ProgressDialog.show(ImageDownladerActivity.this,
"Wait", "Downloading Image");
}
@Override
protected void onPostExecute(Bitmap result) {
Log.i("Async-Example", "onPostExecute Called");
downloadedImg.setImageBitmap(result);
simpleWaitDialog.dismiss();
}
private Bitmap downloadBitmap(String url) {
// initilize the default HTTP client object
final DefaultHttpClient client = new DefaultHttpClient();
//forming a HttpGet request
final HttpGet getRequest = new HttpGet(url);
try {
HttpResponse response = client.execute(getRequest);
//check 200 OK for success
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w("ImageDownloader", "Error " + statusCode +
" while retrieving bitmap from " + url);
return null;
}
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
// getting contents from the stream
inputStream = entity.getContent();
// decoding stream data back into image Bitmap that android understands
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (Exception e) {
// You Could provide a more explicit error message for IOException
getRequest.abort();
Log.e("ImageDownloader", "Something went wrong while" +
" retrieving bitmap from " + url + e.toString());
}
return null;
}
}
}
Поскольку в настоящее время для примеров нет поля комментариев (или я его не нашел или у меня нет разрешения на это), вот несколько комментариев об этом:
Это хороший пример того, что можно сделать с помощью AsyncTask.
Однако в настоящее время в этом примере возникают проблемы с
- возможные утечки памяти
- приложение, если произошел поворот экрана незадолго до завершения асинхронной задачи.
Подробнее см .:
- Передача активности как WeakReference во избежание утечек памяти
- http://stackoverflow.com/documentation/android/117/asynctask/5377/possible-problems-with-inner-async-tasks
- Избегайте утечки активности с помощью AsyncTask
Передача активности как WeakReference во избежание утечек памяти
Для AsyncTask обычно требуется ссылка на вызвавшуюся активность.
Если AsyncTask является внутренним классом Activity, вы можете напрямую ссылаться на него и любые переменные / методы-члены.
Если, однако, AsyncTask не является внутренним классом Activity, вам нужно будет передать ссылку Activity на AsyncTask. Когда вы это сделаете, одна потенциальная проблема, которая может возникнуть, заключается в том, что AsyncTask сохранит ссылку для Activity, пока AsyncTask не завершит свою работу в фоновом потоке. Если действие завершено или убито до того, как будет выполняться фоновый поток AsyncTask, AsyncTask все равно будет ссылаться на Activity, поэтому сбор мусора невозможен.
В результате это приведет к утечке памяти.
Чтобы этого не произошло, используйте ссылку WeakReference в AsyncTask вместо прямой ссылки на Activity.
Вот пример AsyncTask, который использует WeakReference:
private class MyAsyncTask extends AsyncTask<String, Void, Void> {
private WeakReference<Activity> mActivity;
public MyAsyncTask(Activity activity) {
mActivity = new WeakReference<Activity>(activity);
}
@Override
protected void onPreExecute() {
final Activity activity = mActivity.get();
if (activity != null) {
....
}
}
@Override
protected Void doInBackground(String... params) {
//Do something
String param1 = params[0];
String param2 = params[1];
return null;
}
@Override
protected void onPostExecute(Void result) {
final Activity activity = mActivity.get();
if (activity != null) {
activity.updateUI();
}
}
}
Вызов AsyncTask из Activity:
new MyAsyncTask(this).execute("param1", "param2");
Вызов AsyncTask из фрагмента:
new MyAsyncTask(getActivity()).execute("param1", "param2");
Порядок исполнения
При первом вводе AsyncTasks
выполнялись последовательно на одном фоновом потоке. Начиная с DONUT
, это было изменено на пул потоков, позволяющий нескольким задачам работать параллельно. Начиная с HONEYCOMB
, задачи выполняются в одном потоке, чтобы избежать ошибок обычного приложения, вызванных параллельным выполнением.
Если вы действительно хотите выполнить параллельное выполнение, вы можете вызвать executeOnExecutor(java.util.concurrent.Executor, Object[])
с помощью THREAD_POOL_EXECUTOR
.
SERIAL_EXECUTOR -> Исполнитель, выполняющий задачи по очереди в последовательном порядке.
THREAD_POOL_EXECUTOR -> Исполнитель, который может использоваться для одновременного выполнения задач.
образец :
Task task = new Task();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, data);
else
task.execute(data);
AsyncTask: последовательное выполнение и параллельное выполнение задачи
AsyncTask является абстрактным классом и не наследует класс Thread
. Он имеет абстрактный метод doInBackground(Params... params)
, который переопределяется для выполнения задачи. Этот метод вызывается из AsyncTask.call()
.
Исполнитель является частью пакета java.util.concurrent
.
Кроме того, AsyncTask содержит 2 Executor
THREAD_POOL_EXECUTOR
Он использует рабочие потоки для выполнения задач параллельно.
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
SERIAL_EXECUTOR
Он выполняет задачу поочередно, то есть один за другим.
private static class SerialExecutor implements Executor { }
Оба Executor
s является статическим, следовательно , только один THREAD_POOL_EXECUTOR
и один SerialExecutor
объекты существуют, но вы можете создать несколько AsyncTask
объектов.
Поэтому, если вы попытаетесь выполнить несколько фоновых задач с помощью стандартного Executor ( SerialExecutor
), эта задача будет очереди и будет выполняться последовательно.
Если вы попытаетесь выполнить несколько фоновых задач с помощью THREAD_POOL_EXECUTOR
, они будут выполняться параллельно.
Пример:
public class MainActivity extends Activity {
private Button bt;
private int CountTask = 0;
private static final String TAG = "AsyncTaskExample";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (Button) findViewById(R.id.button);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
BackgroundTask backgroundTask = new BackgroundTask ();
Integer data[] = { ++CountTask, null, null };
// Task Executed in thread pool ( 1 )
backgroundTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, data);
// Task executed Serially ( 2 )
// Uncomment the below code and comment the above code of Thread
// pool Executor and check
// backgroundTask.execute(data);
Log.d(TAG, "Task = " + (int) CountTask + " Task Queued");
}
});
}
private class BackgroundTask extends AsyncTask<Integer, Integer, Integer> {
int taskNumber;
@Override
protected Integer doInBackground(Integer... integers) {
taskNumber = integers[0];
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d(TAG, "Task = " + taskNumber + " Task Running in Background");
publishProgress(taskNumber);
return null;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(Integer aLong) {
super.onPostExecute(aLong);
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.d(TAG, "Task = " + (int) values[0]
+ " Task Execution Completed");
}
}
}
Выполните несколько раз кнопку «Пуск», чтобы запустить задачу и увидеть результат.
Задача Выполняется в пуле потоков (1)
Для выполнения каждой задачи требуется 1000 мс.
При t = 36s задачи 2, 3 и 4 ставятся в очередь и начинают выполняться также потому, что они выполняются параллельно.
08-02 19:48:35.815: D/AsyncTaskExample(11693): Task = 1 Task Queued
08-02 19:48:35.815: D/AsyncTaskExample(11693): Task = 1 Task Running in Background
08-02 19:48:**36.025**: D/AsyncTaskExample(11693): Task = 2 Task Queued
08-02 19:48:**36.025**: D/AsyncTaskExample(11693): Task = 2 Task Running in Background
08-02 19:48:**36.165**: D/AsyncTaskExample(11693): Task = 3 Task Queued
08-02 19:48:**36.165**: D/AsyncTaskExample(11693): Task = 3 Task Running in Background
08-02 19:48:**36.325**: D/AsyncTaskExample(11693): Task = 4 Task Queued
08-02 19:48:**36.325**: D/AsyncTaskExample(11693): Task = 4 Task Running in Background
08-02 19:48:**36.815**: D/AsyncTaskExample(11693): Task = 1 Task Execution Completed
08-02 19:48:**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Queued
08-02 19:48:**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Running in Background
08-02 19:48:37.025: D/AsyncTaskExample(11693): Task = 2 Task Execution Completed
08-02 19:48:37.165: D/AsyncTaskExample(11693): Task = 3 Task Execution Completed
----------
Комментарий Task Executed in thread pool
(1) и раскомментировании Task executed Serially
(2).
Выполните несколько раз кнопку «Пуск», чтобы запустить задачу и увидеть результат.
Он выполняет задачу последовательно, поэтому каждая задача запускается после выполнения текущей задачи. Следовательно, когда выполнение задачи 1 завершается, в фоновом режиме запускается только Task 2. Наоборот.
08-02 19:42:57.505: D/AsyncTaskExample(10299): Task = 1 Task Queued
08-02 19:42:57.505: D/AsyncTaskExample(10299): Task = 1 Task Running in Background
08-02 19:42:57.675: D/AsyncTaskExample(10299): Task = 2 Task Queued
08-02 19:42:57.835: D/AsyncTaskExample(10299): Task = 3 Task Queued
08-02 19:42:58.005: D/AsyncTaskExample(10299): Task = 4 Task Queued
08-02 19:42:58.155: D/AsyncTaskExample(10299): Task = 5 Task Queued
08-02 19:42:58.505: D/AsyncTaskExample(10299): Task = 1 Task Execution Completed
08-02 19:42:58.505: D/AsyncTaskExample(10299): Task = 2 Task Running in Background
08-02 19:42:58.755: D/AsyncTaskExample(10299): Task = 6 Task Queued
08-02 19:42:59.295: D/AsyncTaskExample(10299): Task = 7 Task Queued
08-02 19:42:59.505: D/AsyncTaskExample(10299): Task = 2 Task Execution Completed
08-02 19:42:59.505: D/AsyncTaskExample(10299): Task = 3 Task Running in Background
08-02 19:43:00.035: D/AsyncTaskExample(10299): Task = 8 Task Queued
08-02 19:43:00.505: D/AsyncTaskExample(10299): Task = 3 Task Execution Completed
08-02 19:43:**00.505**: D/AsyncTaskExample(10299): Task = 4 Task Running in Background
08-02 19:43:**01.505**: D/AsyncTaskExample(10299): Task = 4 Task Execution Completed
08-02 19:43:**01.515**: D/AsyncTaskExample(10299): Task = 5 Task Running in Background
08-02 19:43:**02.515**: D/AsyncTaskExample(10299): Task = 5 Task Execution Completed
08-02 19:43:**02.515**: D/AsyncTaskExample(10299): Task = 6 Task Running in Background
08-02 19:43:**03.515**: D/AsyncTaskExample(10299): Task = 7 Task Running in Background
08-02 19:43:**03.515**: D/AsyncTaskExample(10299): Task = 6 Task Execution Completed
08-02 19:43:04.515: D/AsyncTaskExample(10299): Task = 8 Task Running in Background
08-02 19:43:**04.515**: D/AsyncTaskExample(10299): Task = 7 Task Execution Completed