Android 中的 AsyncTask

Overview

AsyncTask 能够让我们不用操作 threads 和 handlers 的情况下,在 UI 线程中方便的执行耗时操作,并且返回结果到 UI 线程。

AsyncTask 理论上被用来执行 短时(通常情况下,只需几秒的操作)的操作。如果你需要长时间的执行某一操作,强烈推荐你使用 java.util.concurrent 包下的 Executor, ThreadPoolExecutorFutureTask.

你在定义AsyncTask时需要定义三个泛型参数:

  • Called Params - 传入的参数
  • Progress - 执行中的参数
  • Result - 返回值参数

4 个方法:

  • onPreExecute()
  • doInBackground()
  • onProgressUpdate()
  • onPostExecute()

如何使用?

AsyncTask 必须作为一个子类去使用。其中, doInBackgournd(Params...) 是必须实现的方法,大部分情况下,我们还需要实现 onPostExecute(Result) 方法.

下面是一个使用的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}

protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}

protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}

然后,就是执行这个 AsyncTask:

1
new DownloadFilesTask().execute(url1, url2, url3);

AsyncTask 的泛型参数

  • 1.Params 执行前传入的参数
  • 2.Progress 执行中传入的参数
  • 3.Result 执行完毕后返回的参数

当然,如果你不需要传任何参数,使用 Void 即可:

1
private class MyTask extends AsyncTask<Void, Void, Void> { ... }

四个方法

  • 1.onPreExecute() UI线程会在任务执行前调用此方法。通常被用来设置与任务相关的操作,比如在用户界面显示一个进度条。
  • 2.doInBackground(Params...)onPreExecute() 执行完毕后,调用此方法,注意,此耗时操作执行在一个后台线程中。 Params 参数会被传入到此方法中,计算的结果必须由这一步返回,并将传回最后一步。在方法中,我们还可以调用 publishProgress(Progress...) 来传递进度,然后我就可以在 onProgressUpdate(Progress...) 的方法中来更新 UI 了。
  • 3.onProgressUpdate(Progress...) 此方法将会在调用了 publishProgress(Progress...) 后,由UI线程来调用。通常被用来在界面上显示执行的进度,例如,它可用于动画显示一个进度栏或在文本字段中显示日志。
  • 4.onPostExecute(Result) 此方法在耗时操作执行完毕后,由UI线程调用。 doInBackground(Params...) 中返回的结果将作为参数传递进来。

取消任务

我们可以通过调用 cancel(boolean) 在任何时候来取消异步任务。Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)

使用它,你需要遵守

  • The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
  • 你必须在 UI 线程中创建任务实例。
  • 你必须在 UI 线程中调用 execute(Params...)
  • 不要手动调用 onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...)
  • 任务只能执行一次(如果你尝试调用第二次,将会抛出异常)

Memory observability

AsyncTask guarantees that all callback calls are synchronized in such a way that the following operations are safe without explicit synchronizations.

  • Set member fields in the constructor or onPreExecute(), and refer to them in doInBackground(Params…).
  • Set member fields in doInBackground(Params…), and refer to them in onProgressUpdate(Progress…) and onPostExecute(Result).

执行顺序

在第一次引入 AsyncTask 时,内部实现使用串行执行单个后台线程。而从 DONUT(甜甜圈)开始,这是更改为允许多个任务并行运行的线程池。从 HONEYCOMB(蜂窝)开始,在单个线程上执行任务并行执行,以避免引起的常见的应用程序错误

如果你真的需要并行执行, 你可以通过 THREAD_POOL_EXECUTOR 来调用 executeOnExecutor(java.util.concurrent.Executor, Object[]) .

本文参考:
http://developer.android.com/reference/android/os/AsyncTask.html

文章有帮助到您?不妨打赏博主一碗拉面或一杯咖啡的小费吧 :-D!