1. 1) Task的實例必須在UI thread中創建
2) execute方法必須在UI thread中調用
3) 不要手動的調用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)這幾個方法
4) 該task只能被執行一次,否則多次調用時將會出現異常。
如果在子線程中創建調用 onPreExecute()也在創建AsyncTask的子線程中執行,doInBackground(Params...)在子線程中執行,onPostExecute(Result)和onProgressUpdate(Progress...)在主線程中
2. AsyncTask對象不可重復使用,也就是說一個AsyncTask對象只能execute()一次,否則會有異常拋出"java.lang.IllegalStateException: Cannot execute task: the task is already running"
AsyncTask源碼如下:
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
3. 在doInBackground()中要檢查isCancelled()的返回值,如果你的異步任務是可以取消的話。
cancel()僅僅是給AsyncTask對象設置了一個標識位,當調用了cancel()后,發生的事情只有:AsyncTask對象的標識位變了,和doInBackground()執行完成后,onPostExecute()不會被回調了,
而doInBackground()和 onProgressUpdate()還是會繼續執行直到doInBackground()結束。所以要在doInBackground()中不斷的檢查 isCancellled()的返回值,當其返回true時就停止執行,
特別是有循環的時候。
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);
return mFuture.cancel(mayInterruptIfRunning);
}
4. 如果要在應用程序中使用網絡,一定不要忘記在AndroidManifest中聲明INTERNET權限,否則會報出很詭異的異常信息,比如上面的例子,如果把INTERNET權限拿掉會拋出"UnknownHostException"。
對比Java SE的Thread
Thread是非常原始的類,它只有一個run()方法,一旦開始,無法停止,它僅適合於一個非常獨立的異步任務,也即不需要與主線程交互,對於其他情況,比如需要取消或與主線程交互,都需添加額外的代碼來實現,
並且還要注意同步的問題。而AsyncTask是封裝好了的,可以直接拿來用,如果你僅執行獨立的異步任務,可以僅實現doInBackground()。
所以,當有一個非常獨立的任務時,可以考慮使用Thread,其他時候,盡可能的用 AsyncTask。
5. 通常使用AsyncTask,是通過繼承這個超類來完成的,如:
class BackgroundTask extends AsyncTask<Object,Object,Object>
{
@Override
protected Object doInBackground(Object... params) {
return null;
}
}
子類必須重載 doInBackground方法。“<>”里面的三個類型,依次代表執行參數類型、進度參數類型和結果參數類型。doInBackground的參數類型必須是執行參數類型,返回的類型必須和結果參數類型。
這三個類型應該根據需要來定,其實用Object也可以,用的時候在做類型轉換。啟動一個AsyncTask,可以在這樣做:
BackgroudTask bt = new BackgroundTask();
bt.execute("param");
使用AsyncTask的容易犯下的錯誤是在doInBackground方法里面直接對UI元素進行操作。如果需要和UI進行交互,可以配合使用publishProgress和onProgressUpdate。比如
@Override
protected Object doInbackground(Object... params)
{
...
publishProgress("20%");
...
publishProgress("80%");
...
return null;
}
protected void onProgressUpdate(Object... progress){
...
textView1.setText((String)progress[0]);
...
}
這里onProgressUpdate是工作在UI線程的。
使用AsyncTask的另一個問題是關於cancel。實際上,單單調用AsyncTask對象的cancel方法,並不能停止doInBackground方法的繼續執行。通常比較接受的方法是設置一個標志位,
也就是在每次執行前檢查一下某個變量的值(或者可以調用isCancelled方法判斷),來決定繼續執行還是停止。這種處理手段對於一些循環性的工作比較有用,但是對於一些循環性弱的工作可能並不怎么有效。
這也算是AsyncTask的一個弱點。和Thread相比,AsyncTask還有一個弱點是效率的問題,這個可以在本文開頭給出的鏈接中找到相關的信息。
6. AsyncTask還有一個問題和onPreExecute方法有關。這個方法是工作在UI線程的。雖然是叫onPreExecute,但是doInBackground方法(也就是實際上的execute),並不會等待onPreExecute方法做完全部操作才開始執行。
所以,一般還是不要用這個方法,可以在調用AsyncTask對象的execute方法之前就把該完成的操作完成,以免引起某些錯誤。
AsyncTask還有一個方法是onPostExecute,這個方法也是工作在UI線程,它是在doInBackground方法執行結束,並返回結果后調用。這個方法里面可以調用UI線程的startActivity,這樣可以實現完成大量后台操作后,
自動跳轉Activity的功能。這個方法里面也可以執行另一個AsyncTask的execute方法。
7. 執行順序:
通過AsyncTask.execute()執行
<1.6 :在1.6(Donut)之前: 在第一版的AsyncTask,任務是串行調度。一個任務執行完成另一個才能執行。由於串行執行任務,使用多個AsyncTask可能會帶來有些問題。
所以這並不是一個很好的處理異步(尤其是需要將結果作用於UI試圖)操作的方法
1.6 -- 2.3: 所有的任務並發執行,這會導致一種情況,就是其中一條任務執行出問題了,會引起其他任務出現錯誤.
> 3.0 :AsyncTask又修改為了順序執行,並且新添加了一個函數 executeOnExecutor(Executor),如果您需要並行執行,則只需要調用該函數,並把參數設置為並行執行即可。
並行執行asyncTask.executeOnExecutor(Executors.newFixedThreadPool(7), "");
AsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)你也可以采用這個系統提供的線程池來處理你的任務
默認這個線程池是並發處理任務的,也就是不按順序來.核心為5條,最大128條
