去五金店買個鑽,不是由於咱們須要鑽,咱們只需須要孔,既然五金店沒法買孔,退而求其次,買打孔的工具。一樣的對於後臺線程,咱們真正須要的是可以在UI主線程外進行處理,Android提供一個讓程序員編寫後臺操做更爲容易和透明AsyncTask。java
使用AsyncTask,須要建立AsyncTask的資料,並實現其中的抽象方法以及重寫某些方法。利用AsyncTask咱們不須要本身來寫後臺線程,無需終結後臺線程,例如stop()的方式。AsyncTask的方式對無限循環的方式並不太合適,可能更合適使用Runnable或者Thread。android
對於初次使用的人,AsyncTask看起來有一些複雜。咱們先學些AsyncTask的基本狀況,而後給出一個小例子來驗證。程序員
AsyncTaskweb
AsyncTask中有三個參數(例如class MyTask extends AsyncTask<參數1,參數2,參數3>{})編程
其中參數1和參數2是一個varags,例如String…,至關於String[]。數組
對於AsyncTask的使用步驟以下:安全
一個小例子網絡
有一個ListView的小例子,一開始List中沒有內容,經過一個AsyncTask逐步在List中加入條目。ide
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和內存,是有代價的,咱們應該確保它處理的時候更爲有效。