Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中AsyncTask與handler用法實例分析

Android中AsyncTask與handler用法實例分析

編輯:關於Android編程

本文實例講述了Android中AsyncTask與handler用法。分享給大家供大家參考,具體如下:

首先,我們得明確下一個概念,什麼是UI線程。顧名思義,ui線程就是管理著用戶界面的那個線程!

android的ui線程操作並不是安全的,並且和用戶直接進行界面交互的操作都必須在ui線程中進行才可以。這種模式叫做單線程模式。

我們在單線程模式下編程一定要注意:不要阻塞ui線程、確保只在ui線程中訪問ui組件

當我們要執行一個復雜耗時的算法並且最終要將計算結果反映到ui上時,我們會發現,我們根本沒辦法同時保證上面的兩點要求;我們肯定會想到開啟一個新的線程,讓這個復雜耗時的任務到後台去執行,但是執行完畢了呢?我們發現,我們無法再與ui進行交互了。
為了解決這種情況,android為我們提供了很多辦法。

1)、handler和message機制:通過顯示的拋出、捕獲消息與ui進行交互;

2)、Activity.runOnUiThread(Runnable):如果當前線程為ui線程,則立即執行;否則,將參數中的線程操作放入到ui線程的事件隊列中,等待執行。

3)、View.post(Runnable):將操作放入到message隊列中,如果放入成功,該操作將會在ui線程中執行,並返回true,否則返回false

4)、View.postDelayed(Runnable, long)跟第三條基本一樣,只不過添加了一個延遲時間。

5)、android1.5以後為我們提供了一個工具類來搞定這個問題AsyncTask.

AsyncTask是抽象類,定義了三種泛型類型 Params,Progress,Result。

Params 啟動任務執行的輸入參數,比如HTTP請求的URL
Progress 後台任務執行的百分比。
Result 後台執行任務最終返回的結果,比如String

用程序調用,開發者需要做的就是實現這些方法。

1) 子類化AsyncTask
2) 實現AsyncTask中定義的下面一個或幾個方法

onPreExecute(),該方法將在執行實際的後台操作前被UI thread調用。可以在該方法中做一些准備工作,如在界面上顯示一個進度條。
doInBackground(Params…),將在onPreExecute 方法執行後馬上執行,該方法運行在後台線程中。這裡將主要負責執行那些很耗時的後台計算工作。可以調用 publishProgress方法來更新實時的任務進度。該方法是抽象方法,子類必須實現。
onProgressUpdate(Progress…),在publishProgress方法被調用後,UI thread將調用這個方法從而在界面上展示任務的進展情況,例如通過一個進度條進行展示。
onPostExecute(Result),在doInBackground 執行完成後,onPostExecute 方法將被UI thread調用,後台的計算結果將通過該方法傳遞到UI thread.

為了正確的使用AsyncTask類,以下是幾條必須遵守的准則:

1) Task的實例必須在UI thread中創建
2) execute方法必須在UI thread中調用
3) 不要手動的調用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)這幾個方法
4) 該task只能被執行一次,否則多次調用時將會出現異常

package cn.com.chenzheng_java; 
import android.os.AsyncTask; 
/** 
 * 
 * @author chenzheng_java 
 * @description 異步任務AcyncTask示例 
 *   
 */ 
public class MyAsyncTask extends AsyncTask<String, Integer, Object> { 
 /** 
 * 該方法由ui線程進行調用,用戶可以在這裡盡情的訪問ui組件。 
 * 很多時候,我們會在這裡顯示一個進度條啥的,以示後台正在 
 * 執行某項功能。 
 */ 
 @Override 
 protected void onPreExecute() { 
 super.onPreExecute(); 
 } 
 /** 
 * 該方法由後台進程進行調用,進行主要的耗時的那些計算。 
 * 該方法在onPreExecute方法之後進行調用。當然在執行過程中 
 * 我們可以每隔多少秒就調用一次publishProgress方法,更新 
 * 進度信息 
 */ 
 @Override 
 protected Object doInBackground(String... params) { 
 return null; 
 } 
 /** 
 * doInBackground中調用了publishProgress之後,ui線程就會 
 * 調用該方法。你可以在這裡動態的改變進度條的進度,讓用戶知道 
 * 當前的進度。 
 */ 
 @Override 
 protected void onProgressUpdate(Integer... values) { 
 super.onProgressUpdate(values); 
 } 
 /** 
 * 當doInBackground執行完畢之後,由ui線程調用。可以在這裡 
 * 返回我們計算的最終結果給用戶。 
 */ 
 @Override 
 protected void onPostExecute(Object result) { 
 super.onPostExecute(result); 
 } 
}

下面介紹最本質的多線程:hanlder和message機制:

為何需要多線程:

在日常應用中,我們通常需要處理一些“後台,用戶不可見”的操作,例如說,我們需要下載一個音樂,要是你的應用必須等用戶下載完成之後才可以進行別的操作,那肯定讓用戶非常的不爽。這時候,我們通常的做法是,讓這些操作去後台執行,然後等後台執行完畢之後,再給用戶彈出相應的提示信息。這時候,我們就需要使用多線程機制,然後通過創建一個新的線程來執行這些操作。

明白了,實現需求,我們就准備著手實現了。但是,經過進一步的了解,我們悲劇的發現,android中的線程機制是,只能在UI線程中和用戶進行交互。當我們創建了一個新線程,執行了一些後台操作,執行完成之後,我們想要給用戶彈出對話框以確認,但是卻悲劇的發現,我們根本無法返回UI主線程了。(UI線程就是你當前看到的這些交互界面所屬的線程)。

這時候,我們如果想要實現這些功能,我們就需要一個android為我們提供的handler和message機制。

先講解下編程機制:

我們通常在UI線程中創建一個handler,handler相當於一個處理器,它主要負責處理和綁定到該handler的線程中的message。每一個handler都必須關聯一個looper,並且兩者是一一對應的,注意,這點很重要哦!此外,looper負責從其內部的messageQueue中拿出一個個的message給handler進行處理。因為我們這裡handler是在UI線程中實現的,所以經過這麼一個handler、message機制,我們就可以回到UI線程中了。

handler:處理後台進程返回數據的工作人員。
message:後台進程返回的數據,裡面可以存儲bundle等數據格式
messageQueue:是線程對應looper的一部分,負責存儲從後台進程中拋回的和當前handler綁定的message,是一個隊列。
looper:looper相當於一個messageQueue的管理人員,它會不停的循環的遍歷隊列,然後將符合條件的message一個個的拿出來交給handler進行處理。

注意,handler是在UI線程中聲明的,如果我們直接用類似代碼執行一個線程的話,實際上並沒有創建一個新的線程,因為handler已經跟默認的UI線程中的looper綁定了。

如果有興趣的話,可以去看下Handler的默認空構造函數便知道原因了,裡面直接綁定了當前UI線程的looper。

下面給出一個比較簡單,並且實用的實例。

public class MainActivity extends Activity implements OnClickListener { 
  private Button btnTXT; 
  private TextView tvTXT; 
  private StringBuffer returnMsg; 
  @Override 
  public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    btnTXT = (Button)findViewById(R.id.btnTXT); 
    tvTXT = (TextView)findViewById(R.id.tvTXT); 
    btnTXT.setOnClickListener(this);     
  } 
  @Override 
  public void onClick(View v) { 
    returnMsg = new StringBuffer(); 
    // 創建一個包含Looper的線程,這裡如果沒有HandlerThread的調用,會直接將後邊的MyRunnable放到UI線程隊列(myHandler.post(new MyRunnable())) 
    HandlerThread handlerThread = new HandlerThread("handler_thread"); 
    handlerThread.start();   // 啟動自定義處理線程 
    myHandler = new MyHandler(handlerThread.getLooper());    // 將handler綁定到新線程  
    myHandler.post(new MyRunnable());    // 在新線程中執行任務  
  } 
  /** 主線程Handler,可以與UI控件交互 */ 
  Handler mainHanlder = new Handler(){ 
    @Override 
    public void handleMessage(Message msg) { 
      if(msg.what == 0) { 
        tvTXT.setText(returnMsg.toString());  // 與主線程控件打交道(直接訪問) 
      } 
    } 
  }; 
  /** 構造Hanlder,不可與UI控件直接交互 */ 
  private MyHandler myHandler = null; 
  private class MyHandler extends Handler{ 
    /** 
     * 使用默認的構造函數,會將handler綁定當前UI線程的looper。 
     * 如果想使用多線程這裡是不能使用默認的構造方法的。 
     */  
    public MyHandler(){ 
      super(); 
    } 
    /** 構造函數,自定義looper */ 
    public MyHandler(Looper looper) { 
      super(looper); 
    } 
    // 處理具體的message消息,繼承自父類的方法 
    @Override 
    public void handleMessage(Message msg) { 
      int what = msg.what;   
      Bundle bundle = (Bundle)msg.obj;      // 提取bundle中的信息 
      String name = bundle.getString("name"); 
      String sex = bundle.getString("sex"); 
      boolean marry = bundle.getBoolean("marray"); 
      int age = bundle.getInt("age"); 
      StringBuffer strBuf = new StringBuffer();    // 拼接bundle信息 
      strBuf.append("what = ").append(what).append("\n\n"); 
      strBuf.append("name = ").append(name).append("\n"); 
      strBuf.append("sex = ").append(sex).append("\n"); 
      strBuf.append("marry = ").append(marry).append("\n"); 
      strBuf.append("age = ").append(age).append("\n\n"); 
      strBuf.append("http://blog.csdn.net/sunboy_2050"); 
      returnMsg = returnMsg.append(strBuf);  // 保存要顯示的結果 
      mainHanlder.sendEmptyMessage(0);    // 向主線程mainHanlder發送消息,與UI控件交互顯示結果 
      super.handleMessage(msg); 
    } 
  } 
  // 構造Runnable,處理後台業務邏輯,如下載 
  private class MyRunnable implements Runnable{ 
    @Override 
    public void run() { 
      try { 
        Message msg = Message.obtain(myHandler);  // 捕獲myHandler消息
        msg.what = 10; 
        Bundle bundle = new Bundle();        // 封裝bundle信息 
        bundle.putString("name", "yanggang"); 
        bundle.putString("sex", "pure boy"); 
        bundle.putBoolean("marry", false); 
        bundle.putInt("age", 18); 
        msg.obj = bundle; 
        long thID = Thread.currentThread().getId(); 
        returnMsg.append(thID).append(" : send msg start...").append("\n"); 
        msg.sendToTarget();   // 向myHandler發送消息 
        Thread.sleep(3000); 
      } catch (Exception e) { 
        Log.i("", "Runnable send msg error..."); 
        e.printStackTrace(); 
      } 
    } 
  } 
}

運行結果:

完整實例代碼代碼點擊此處本站下載。

希望本文所述對大家Android程序設計有所幫助。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved