1. 程式人生 > >Android筆記二十六.Android非同步任務處理(AsyncTask)

Android筆記二十六.Android非同步任務處理(AsyncTask)

一、引言     我們知道Android的UI執行緒主要負責處理使用者的按鍵事件使用者觸屏事件螢幕繪圖事件等,對於其他的操作儘量不要在UI執行緒中實現,因為這些操作很有可能會阻塞UI執行緒,比如一些耗時操作,會導致UI介面停止響應,從而降低了使用者的體驗。所以,為了避免UI執行緒失去響應的問題,Android建議將耗時操作放在新執行緒中完成,但新執行緒也可能需要動態更新UI元件:比如需要從網上獲取一個網頁,然後在TextView中將其原始碼顯示出來,此時就應該將連線網路,獲取網路資料的操作(耗時)放在新執行緒中完成。     但是,問題來了:當獲取網路資料之後,由於新執行緒不允許直接更新UI元件
,我們該如何更新UI元件資料呢?為了解決新執行緒不能更新UI元件問題,Android提供瞭如下幾種解決方案:
(1)使用Handler訊息傳遞機制實現執行緒之間的通訊(如上一篇文章所述); (2)Activity.runOnUiThread(Runnable); (3)View.post(Runnable); (4)View.postDelayed(Runnable long); (5)非同步任務。又由於(2)~(4)方式有可能導致程式設計有點繁瑣,而非同步任務則可簡化這種操作。 二、AsyncTask簡介     Android的類AsyncTask對執行緒間通訊進行了包裝,提供了簡易的程式設計方式使後臺執行緒和UI執行緒進行通訊:後臺執行緒執行非同步任務,並把操作結果通知UI
。不再需要子執行緒和Handler就可以完成非同步操作並且重新整理使用者介面
1.AsyncTask類     AsyncTask<>是一個抽象類,通常用於被繼承,繼承AsyncTask時需要指定如下三種泛型引數: (1)Params:啟動任務執行輸入引數的型別; (2)Progress:後臺任務完成的進度值(百分比)的型別; (3)Result:後臺執行任務完成後返回結果的型別,如String、Integer; 2.Async類中主要方法 (1)onPreExecute():該方法將在執行實際的後臺操作前UI執行緒呼叫。可以在該方法中做一些準備工作,如在介面上顯示一個進度條,或者一些控制元件的例項化,這個方法可以不用實現。
-----(UI執行緒呼叫,後臺執行緒未啟動,初始化工作) (2)doInBackground(Params...values):將在onPreExecute 方法執行後馬上執行,該方法執行在後臺執行緒中。這裡將主要負責執行那些比較耗時的後臺處理工作。可以呼叫 publishProgress()方法來實時更新任務進度。該方法是抽象方法,子類必須實現。 -----(後臺執行緒呼叫,執行後臺任務)
(3)onProgressUpdate(Progress...values):在publishProgress方法被呼叫後,UI 執行緒將呼叫這個方法從而在介面上展示任務的進展情況,例如通過一個進度條進行展示。 -----(UI執行緒呼叫,展現後臺任務進展)
(4)onPostExecute(Result):在doInBackground 執行完成後,onPostExecute 方法將被UI線程呼叫,後臺的計算結果(doInBackground方法返回值)將通過該方法傳遞到UI執行緒,並且在介面上展示給使用者。 -----(UI執行緒呼叫,顯示後臺執行緒執行結果) (5) onCancelled():在使用者取消執行緒操作的時候呼叫。在主執行緒中呼叫onCancelled()的時候呼叫。 -----(UI執行緒呼叫,取消後臺執行緒)  三、非同步任務處理開發步驟 1.建立AsyncTask的子類,併為三個泛型引數指定型別。如果某個泛型引數不需要指定型別,則將它指定為Void。 2.根據需要實現AsyncTask上述五中方法; 3.呼叫AsyncTask子類的例項的execute(Params... params)開始執行耗時任務。 另外,使用AsyncTask類需要遵守的以下準則 (1)Task的例項必須在UI執行緒中建立; (2)execute(Params...)方法必須在UI執行緒中呼叫; (3)不要手動的呼叫onPreExecute(), onPostExecute(Result),doInBackground(Params...),onProgressUpdate(Progress...)這幾個方法,需要在UI執行緒中例項化這個task來呼叫; (4)該task只能被執行一次,否者多次呼叫時將會出現異常 四、原始碼實戰 1.實現功能 2.原始碼實現 (1)MainActivity.java 功能:用以獲取介面元件,例項化一個AsyncTask子類物件並呼叫其exeute(Integer....params)方法以指定引數params執行一個任務。
package com.example.android_asynctask;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends Activity {
 private Button downbtn;
 private TextView textView;
 private ProgressBar progressBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        downbtn = (Button)findViewById(R.id.download);
        textView = (TextView)findViewById(R.id.text);
        progressBar = (ProgressBar)findViewById(R.id.progressBar);
        final DownloadTest download = new DownloadTest(textView,progressBar);	//獲取一個DownloadTest物件,並傳遞元件物件引數
        downbtn.setOnClickListener(new OnClickListener()
        {
   @Override
   public void onClick(View v) {
    download.execute(200);
   }
        });
       
    }
}
(2)DownloadTest.java 功能:繼承於AsyncTask的子類,其中onPreExecute()作用是為執行後臺執行緒(子執行緒)完成初始化工作;doInBackground方法執行後臺執行緒;onProgressUpdate方法更新UI;onPostExecute方法處理後臺執行緒執行結果。
package com.example.android_asynctask;
import android.graphics.Color;
import android.os.AsyncTask;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
public class DownloadTest extends AsyncTask<Integer,Integer,String>
{
 private TextView tv;
 private ProgressBar pb;
 //帶引數構造方法
 DownloadTest(TextView text,ProgressBar bar)
 {
  this.tv = text;
  this.pb = bar;
 }
 //不帶引數構造方法
 DownloadTest()
 {
 }
 /*1.onPreExecute方法
  * 為子執行緒(後臺)執行初始化相關內容
  */
 protected void onPreExecute() {
      tv.setVisibility(View.VISIBLE);	 //設定顯示文字元件
      pb.setVisibility(View.VISIBLE);	 //設定顯示進度條
      super.onPreExecute();
 }
 /*2.doInBackground方法
  *  執行一個後臺執行緒,該執行緒實現每arg0[0]毫秒呼叫一次onProgressUpdate方法
  */
 protected String doInBackground(Integer... arg0) {
  for(int i=0;i<100;i++)
  {
   publishProgress(i);	 //呼叫onProgressUpdate方法並傳遞引數i
   try {
    Thread.sleep(arg0[0]);	//累加一次,執行緒休眠argo[0]毫秒
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  return "下載完畢";	 //後臺子執行緒執行完畢後,返回的值
 }
 /*3.onProgressUpdate方法
  * 呼叫publishProgress(i)時呼叫該方法,並傳遞引數i給形參values[0]*/

 @Override
 protected void onProgressUpdate(Integer... values) {
  pb.setProgress(values[0]);	 //設定進度條值
  tv.setText("已經下載"+values[0]+"%");	 //文字元件顯示提示資訊
  super.onProgressUpdate(values);
 }
 /*4.onPostExecute
  * 處理後臺執行緒得到的結果
  * */
 protected void onPostExecute(String result) {
  pb.setVisibility(View.INVISIBLE);	//隱藏進度條
  tv.setVisibility(View.VISIBLE);	//顯示UI文字顯示框元件
  tv.setText(result);
  tv.setTextSize(20);
  tv.setTextColor(Color.RED);
  super.onPostExecute(result);
 }
}


效果演示:
原始碼分析:     通過原始碼我們可以知道,主執行緒通過呼叫AsyncTask子類的execute()方法,進而呼叫AsyncTask子類的onPreExecute方法,用以再執行後臺執行緒之前為其初始化相關內容。然後,在新建立的子執行緒中呼叫doInBackground()方法實現後臺執行緒功能並通過publishProgress()方法呼叫onProgressUpdate()方法更新UI內容,最後在主線中執行onPostExecute方法來處理後臺執行緒執行的結果。 注意:其中只有doInBackground()方法,以及publishProgress()方法是在子執行緒中執行的,其他的方法都是在主執行緒中執行的,所以可以在這些方法中更新介面元件。