AsyncTask可以用來正確和方便的使用UI線程。這個類允許執行背景操作和公布結果用法:AsyncTask必須是子類。 這個子類起碼要重載 doInBackgroud(Params...), 一般都重載 onPostExecute(Result) 。這裡是子類使用的例子:
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"); } }
一旦建立,執行是很簡單的
new DownloadFilesTask().execute(url1, url2, url3);
非同步任務的通用類型非同步任務使用的三種類型:1. Params
,
執行任務的參數的類型2. Progress
,
在後台運行期間執行的進程3.
Result
,
後台運行返回的結果
不是所有的類型都會被使用。
標記一個未使用的類型,簡單的聲明為 Void
即可。
private class MyTask extends AsyncTask<Void, Void, Void> { ... }
The 4 steps
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute()
,
invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...)
,
invoked on the background thread immediately after onPreExecute()
finishes
executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step.
This step can also use publishProgress(Progress...)
to
publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...)
step.
onProgressUpdate(Progress...)
,
invoked on the UI thread after a call to publishProgress(Progress...)
.
The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
onPostExecute(Result)
,
invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
Cancelling a task
A task can be cancelled at any time by invoking 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.)
Threading rules
There are a few threading rules that must be followed for this class to work properly:
- The AsyncTask class must be loaded on the UI thread. This is done automatically as of
JELLY_BEAN
.
- The task instance must be created on the UI thread.
execute(Params...)
must
be invoked on the UI thread.
- Do not call
onPreExecute()
, onPostExecute(Result)
, doInBackground(Params...)
, onProgressUpdate(Progress...)
manually.
- The task can be executed only once (an exception will be thrown if a second execution is attempted.)
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)
.
Order of execution
When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT
,
this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting with HONEYCOMB
,
tasks are executed on a single thread to avoid common application errors caused by parallel execution.
If you truly want parallel execution, you can invoke executeOnExecutor(java.util.concurrent.Executor,
Object[])
with THREAD_POOL_EXECUTOR
.