前言android
咱們知道Android的UI主線程主要負責處理用戶的按鍵事件、用戶的觸屏事件以及屏幕繪圖事件等;既然UI老人家都這麼忙了,咱們這些開發者確定不能不識趣的去添亂阻塞UI線程什麼的,不然UI界面萬一中止響應了呢——這不是招罵的節奏麼?!因此咱們知道用Handler+Thread的方法,在子線程中處理耗時的任務,任務完成後經過Handler通知UI主線程更新UI界面,皆大歡喜有木有。網絡
但是這樣,仍是有某些人以爲用Handler+Thread的代碼會比較繁瑣,固然這個某些人裏面包括咱們偉大的谷歌。因此AsyncTask(異步任務)在Android 1.5中橫空出世;相對於Handler來講,因爲比較好的封裝,AsyncTask顯得更加輕量級一點,適用於簡單的異步處理;固然使用起來也比較簡潔,果真是谷歌的親兒子!異步
概述ide
AsyncTask是一個抽象類,一般是被繼承的命。AsyncTask的內部會維持一個靜態的線程池,每一個後臺任務天然也會被提交到線程池中運行,同時也使用Handler+Thread的機制來調用AsyncTask的各個回調方法;回調方法是在主線程運行的,因此該幹什麼咱們都懂(~ o ~)~zZ(趕忙跟UI界面套近乎呀)。函數
咱們知道AsyncTask<Params, Progress, Result>是抽象類,咱們能夠在這裏面看出它支持三種泛型:佈局
一、Params:咱們的AsyncTask要開始幹活時,咱們給他的輸入的參數的類型,也就是傳遞給後臺的參數this
二、Progress:AsyncTask向咱們報告它幹活進度的參數類型,舉個例子就是下載進度的百分比spa
三、Result:後臺執行任務完成,返回的結果的參數類型線程
若是某個泛型咱們不須要指定,咱們能夠大大方方的指定Void,沒事AsyncTask不會傷心滴。code
固然谷歌也幫咱們將AsyncTask的後臺任務運行的五種狀態,分別是:一、準備運行,二、正在後臺運行,三、進度更新,四、完成後臺任務,五、取消任務。每種狀態在AsyncTask中各有相應的回調方法。
一、準備運行:onPreExecute(),在任務開啓時該回調方法當即在UI線程中被調用,同時也是在執行後臺耗時操做前被調用;一般該方法用於完成一些初始化工做,好比在界面上顯示進度條等。
二、正在後臺運行:doInBackground(Params...),該回調函數由後臺線程在onPreExecute()方法執行結束後當即調用,重寫該方法就是後臺線程將要完成的耗時任務;因爲是由後臺線程調用,因此咱們不能直接在這裏更新UI界面,應該使用publishProgress(Progress...)觸發回調方法onProgressUpdate(Progress...)進行進度更新;任務計算的結果必須由該函數返回,並被傳遞到onPostExecute()中。
三、進度更新:onProgressUpdate(Progress...),在doInBackground()中調用publishProgress()方法更新任務的執行進度,將會在主線程中觸發該方法,通常用於動態地顯示一個進度條。
四、完成後臺任務:onPostExecute(Result),當doInBackground()完成後,系統會自動調用onPostExecute()方法,並將doInBackground()的返回值傳遞給該方法。
五、取消任務:onCancelled (),在調用AsyncTask的cancel()方法時調用。
案例
參考代碼:
public class MainActivity extends ActionBarActivity implements OnClickListener{ private Button startdownload; private ProgressBar probar; private TextView tv; private DownTask task; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startdownload = (Button) findViewById(R.id.startdownload); probar = (ProgressBar) findViewById(R.id.probar); tv = (TextView) findViewById(R.id.tv); startdownload.setOnClickListener(this); } @Override public void onClick(View v) { task = new DownTask();//同一個AsyncTask的execute只能調用一次 task.execute("輸入參數,可爲空");//調用execute後將會回調onPreExecute方法 } class DownTask extends AsyncTask<String, Integer, String>{ @Override//該方法非在主線程運行,可進行耗時操做,不可更新UI界面,其餘方法爲主線程運行 protected String doInBackground(String... params) {//params爲execute輸入的參數 for(int i = 1; i <= 100; i++){ try {//模擬下載操做 Thread.sleep(333); publishProgress(i);//傳遞參數i並觸發onProgressUpdate回調方法 } catch (InterruptedException e) { e.printStackTrace(); } } String result = "任務已完成"; return result;//將調用onPostExecute,並將result傳給該回調方法 } @Override protected void onPreExecute() {//該回調方法執行完畢後,將會調用doInBackground probar.setMax(100); probar.setProgress(0); tv.setText("開始下載"); } @Override protected void onPostExecute(String result) {//doInBackground結束後回調該方法,結束。 Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show(); tv.setText("下載完成"); } @Override protected void onProgressUpdate(Integer... values) {//通知UI界面更新 probar.setProgress(values[0]); } } }
佈局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/startdownload" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="開始下載"/> <ProgressBar android:id="@+id/probar" android:layout_width="match_parent" android:layout_height="wrap_content" style="@android:style/Widget.ProgressBar.Horizontal" /> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#000000" android:textSize="20sp" /> </LinearLayout>
代碼講解:
一、點擊Button後先實例化一個AsyncTask的繼承子類,此時將會建立一個task。接下來變執行execute(params)方法啓動異步任務。(同一個AsyncTask的實例只能執行execute一次,屢次執行會拋出錯誤)。
二、在execute()被執行後,將會觸發onPreExecute()回調方法,設置進度條的初始屬性。在onPreExecute()執行完畢後,將會在後臺線程開始執行doInBackground(params),該方法接收execute傳入的參數,進行耗時操做,這裏是模擬網絡文件下載任務。
三、doInBackground()在後臺線程運行中,若是須要與UI主線程交互更新進度,能夠調用publishProgress(values)方法,將會觸發位於UI主線程運行的onProgressUpdate(values)的回調方法,代碼中在這裏更新進度條的進度。
四、 當後臺任務執行完成後,調用onPostExecute(Result),傳入的參數是doInBackground()中返回的對象。
注意事項
一、不要在同一個AsyncTask實例中屢次執行execute(),正確的方法是new一個AsyncTask執行一次execute()。
二、耗時任務必定要在doInBackground()中處理,不要在其餘回調方法中處理耗時任務以避免引發UI主線程的阻塞。
三、不要再doInBackground()中更新UI界面,應該經過publishProgress()調用回調方法更新UI。
四、onCancelled()只能觸發AsyncTask的cancel()方法,並沒有法取消正在線程池運行的線程任務,但能夠經過標誌位來中止線程任務。
五、在不一樣的android版本中,AsyncTask多任務運行,有些是能夠並行有些則是順序執行,不過在高版本Android中,能夠經過指定參數設置線程池執行規則。
六、AsyncTask適合處理短期的操做,長時間的操做,好比下載一個很大的視頻,這就須要你使用本身的線程來下載,不論是斷點下載仍是其它的。