1. 程式人生 > >Android學習筆記 三二 執行緒 後臺非同步任務AsyncTask

Android學習筆記 三二 執行緒 後臺非同步任務AsyncTask

去五金店買個鑽,不是因為我們需要鑽,我們只需需要孔,既然五金店無法買孔,退而求其次,買打孔的工具。同樣的對於後臺執行緒,我們真正需要的是能夠在UI主執行緒外進行處理,Android提供一個讓程式設計師編寫後臺操作更為容易和透明AsyncTask。

使用AsyncTask,需要建立AsyncTask的資料,並實現其中的抽象方法以及重寫某些方法。利用AsyncTask我們不需要自己來寫後臺執行緒,無需終結後臺執行緒,例如stop()的方式。AsyncTask的方式對無限迴圈的方式並不太合適,可能更合適使用Runnable或者Thread。

對於初次使用的人,AsyncTask看起來有一些複雜。我們先學些AsyncTask的基本情況,然後給出一個小例子來驗證。

AsyncTask

AsyncTask中有三個引數(例如class MyTask extends AsyncTask<引數1,引數2,引數3>{})

  • 引數1:向後臺任務的執行方法傳遞引數的型別
  • 引數2:在後臺任務執行過程中,要求主UI執行緒處理中間狀態,通常是一些UI處理中傳遞的引數型別
  • 引數3:後臺任務執行完返回時的引數型別

其中引數1和引數2是一個varags,例如String…,相當於String[]。

對於AsyncTask的使用步驟如下:

  • 建立一個AsyncTask的子類,物件建立時帶引數(引數1,引數2,引數3)
  • 呼叫物件的excute()時,將啟動後臺程序,執行doInBackground()的程式碼。excute()中所傳遞的引數型別在引數1中描述,屬於正規化定義
  • 如果我們希望在啟動後臺程序中,進行某些初始化的處理,可以override onPreExecute()方法,注意這些程式碼是在UI執行緒中執行的
  • 在執行完後臺程序,我們需要進行某些處理,例如停止某些UI的動態畫面,進度條消失等等,可以重寫onPostExecute()方法,同樣,這些程式碼也是在UI主執行緒中執行。其中將doInBackground()的返回值傳遞作為onPostExecute()引數中,其型別由引數3描述
  • 在執行後臺程序中,如果需要需要向UI執行緒報告某個處理狀態,可以通過publishProgress()來觸發,這樣在UI主執行緒中將執行重寫後的onProgressUpdate()的程式碼,其中傳遞的引數的型別由引數2描述。

一個小例子

有一個ListView的小例子,一開始List中沒有內容,通過一個AsyncTask逐步在List中加入條目。

1)XML檔案:簡單的ListView佈局

<?xml version="1.0" encoding="utf-8"?><LinearLayout ... ...>  <ListView android:id="@android:id/list"    android:layout_width="fill_parent"    android:layout_height="fill_parent" />  </LinearLayout>

2)例子程式碼

public class Chapter15Test3 extends ListActivity{    //這裡是List Item內容,在這個例子中,將在後臺任務中逐個加入    private static String[] items={"lorem", "ipsum", "dolor","sit", "amet", "consectetuer","adipiscing", "elit", "morbi","vel", "ligula", "vitae","arcu", "aliquet", "mollis","etiam", "vel", "erat","placerat", "ante","porttitor", "sodales","pellentesque", "augue","purus"};    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.chapter_8_test2);        //在這個例子中,我們一開始並沒有匯入items的資料,注意item資料為新建的ArrayList,即無內容        setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,new ArrayList<String>()));        //步驟5:建立後臺任務的物件,並通過execute()啟動後臺執行緒,呼叫doInBackground()的程式碼,execute中的引數型別為引數1,這裡我們不需要傳遞任何內容        new AddStringTask().execute();    }    //步驟1:建立AsyncTask子類,引數1是Void的正規化型別,引數2是String的正規化型別,引數3是Void其中引數1:向後臺任務的執行方法傳遞引數的型別;引數2:在後臺任務執行過程中,要求主UI執行緒處理中間狀態,通常是一些UI處理中傳遞的引數型別;引數3:後臺任務執行完返回時的引數型別    private class AddStringTask extends AsyncTask<Void, String,Void>{       //我們加入一個檢測資訊的方法,列印當前在哪個執行緒執行的資訊        private void printInfo(String info){            Log.d("WEI", info + " : Tread is " + Thread.currentThread().getName());        }        //步驟2:實現抽象方法doInBackground(),程式碼將在後臺執行緒中執行,由execute()觸發,由於這個例子並不需要傳遞引數,使用Void...,具體書寫方式為正規化書寫        protected Void/*引數3*/ doInBackground(Void...params/*引數1*/) {            for(String item : items){                //步驟3:通知UI主執行緒執行相關的操作(在onProgressUpdate中定義)                publishProgress(item/*引數2*/);                printInfo("doInBackgound " + item);                SystemClock.sleep(200);            }            return null;        }        //步驟3:定義收到pushProgress()觸發後,在UI主執行緒執行的內容,在本例,將item加入list中。方法中的引數為正規化方式,實質為陣列,由於我們只傳遞了item一個String,要獲取,為values[0]        protected void onProgressUpdate(String... values/*引數2*/) {            printInfo("onProgressUpdate  get param " + values[0]);            ((ArrayAdapter<String>)getListAdapter()).add(values[0]);        }               //步驟4:定義後臺程序執行完後的處理,本例,採用Toast        protected void onPostExecute(Void result/*引數3*/) {            printInfo("onPostExecute");            Toast.makeText(Chapter15Test3.this, "Done!", Toast.LENGTH_SHORT).show();        }              }    }

我們根據printInfo跟蹤各部分程式碼在哪裡執行:doInBackground在後臺執行緒執行,onProgressUpdate()和onPostExecute()在UI主執行緒執行。main就是UI主執行緒,而AsyncTask #1為後臺執行緒,名字不一樣。

需要注意

雖然Android提供後臺任務方便我們處理,是否使用後臺任務,以及如何使用後臺任務,我們要注意下面的內容:

可能在執行後臺執行緒處理中,使用者和UI之間存在互動,這些交換可能會對後臺任務有重要的影響,因此需要通知後臺執行緒,Android提供很多的類來處理,封裝在java.util.concurrent包中,幫助與後臺執行緒的安全通訊。可能在執行後臺執行緒處理中,我們的Activity就已經被kill了,例如有一個電話過來,然後發給簡訊,檢視號碼本。這時系統可能將你的activity踢走,接著後面我們會學習Activity的生命週期,瞭解相關的情況。在程式設計中,出現這種情況,只要有可能,需要將後臺程序關閉。可能在執行後臺執行緒處理中,出現某種錯誤,例如後臺在下載URL,而網路連線中斷了。這種情況下關閉後臺程序可能是最好的處理。此外後臺任務是消耗CPU和記憶體,是有代價的,我們應該確保它處理的時候更為有效。