Handle機制詳解

原文地址:http://blog.csdn.net/kakaxi1o1/article/details/12278499

 

1、Android消息機制一

         Android 有一種叫消息隊列的說法,這裏咱們能夠這樣理解:假如一個隧道就是一個消息隊列,那麼裏面的每一部汽車就是一個一個消息,這裏咱們先忽略掉超車等種種因素,只那麼先進隧道的車將會先出,這個機制跟咱們android 的消息機制是同樣的。java

角色描述android

1. Looper:(至關於隧道) 一個線程能夠產生一個Looper 對象,由它來管理此線程裏的Message Queue( 車隊,消息隧道) 。算法

2. Handler: 你能夠構造Handler 對象來與Looper 溝通,以便push 新消息到Message Queue 裏;或者接收Looper( 從Message Queue 取出) 所送來的消息。編程

3. Message Queue( 消息隊列): 用來存放線程放入的消息。安全

4. 線程:UI thread 一般就是main thread ,而Android 啓動程序時會替它創建一個Message Queue 。數據結構

每個線程裏可含有一個Looper 對象以及一個MessageQueue 數據結構。在你的應用程序裏,能夠定義Handler 的子類別來接收Looper 所送出的消息。多線程

 

在你的Android 程序裏,新誕生一個線程,或執行 (Thread) 時,並不會自動創建其Message Loop 。框架

Android 裏並無Global 的Message Queue 數據結構,例如,不一樣APK 裏的對象不能透過Massage Queue來交換訊息(Message) 。異步

例如:線程A 的Handler 對象能夠傳遞消息給別的線程,讓別的線程B 或C 等能送消息來給線程A( 存於A的Message Queue 裏) 。ide

線程A 的Message Queue 裏的訊息,只有線程A 所屬的對象能夠處理。

使用Looper.myLooper 能夠取得當前線程的Looper 對象。

使用mHandler = new EevntHandler(Looper.myLooper()); 可用來構造當前線程的Handler 對象;其中,EevntHandler 是自已實現的Handler 的子類別。

使用mHandler = new EevntHandler(Looper.getMainLooper()); 可誕生用來處理main 線程的Handler 對象;其中,EevntHandler 是自已實現的Handler 的子類別。

1.  同線程內不一樣組件間的消息傳遞

Looper 類用來管理特定線程內對象之間的消息交換(Message Exchange) 。你的應用程序能夠產生許多個線程。而一個線程能夠有許多個組件,這些組件之間經常須要互相交換訊息。若是有這種須要,您能夠替線程構造一個Looper 對象,來擔任訊息交換的管理工做。Looper 對象會創建一個MessageQueue 數據結構來存放各對象傳來的消息( 包括UI 事件或System 事件等) 。

 

每個線程裏可含有一個Looper 對象以及一個MessageQueue 數據結構。在你的應用程序裏,能夠定義Handler 的子類別來接收Looper 所送出的消息。

同線程不一樣組件之間的消息傳遞:

舉例:

 

 

[java]  view plain copy
 
  1. public class Activity1 extends Activity implements OnClickListener{  
  2.        Button button = null ;  
  3.        TextView text = null ;  
  4.        @Override  
  5.        protected void onCreate(Bundle savedInstanceState) {  
  6.               super .onCreate(savedInstanceState);  
  7.               setContentView(R.layout.activity1 );          
  8.               button = (Button)findViewById(R.id.btn );  
  9.               button.setOnClickListener(this );  
  10.               text = (TextView)findViewById(R.id.content );  
  11.        }  
  12.        public void onClick(View v) {  
  13.               switch (v.getId()) {  
  14.               case R.id.btn :  
  15.                      Looper looper = Looper.myLooper();//取得當前線程裏的looper  
  16.                      MyHandler mHandler = new MyHandler(looper);//構造一個handler使之可與looper通訊  
  17.                      //buton等組件能夠由mHandler將消息傳給looper後,再放入messageQueue中,同時mHandler也能夠接受來自looper消息  
  18.                      mHandler.removeMessages(0);  
  19.                      String msgStr = "主線程不一樣組件通訊:消息來自button";  
  20.                      Message m = mHandler.obtainMessage(1, 1, 1, msgStr);//構造要傳遞的消息  
  21.                      mHandler.sendMessage(m);//發送消息:系統會自動調用handleMessage方法來處理消息  
  22.                      break ;  
  23.                }              
  24.        }       
  25.        private class MyHandler extends Handler{               
  26.               public MyHandler(Looper looper){  
  27.                      super (looper);  
  28.               }  
  29.               @Override  
  30.               public void handleMessage(Message msg) {//處理消息  
  31.                      text.setText(msg.obj.toString());  
  32.               }              
  33.        }  
  34. }  

 

[java]  view plain copy
 
  1.   

   說明:

此程序啓動時,當前線程( 即主線程, main thread) 已誕生了一個Looper 對象,而且有了一個MessageQueue數據結構。

 

[java]  view plain copy
 
  1. looper = Looper.myLooper ();   

 

調用Looper 類別的靜態myLooper() 函數,以取得目前線程裏的Looper 對象.

 

[java]  view plain copy
 
  1. mHandler = new MyHandler (looper);  

 

構造一個MyHandler 對象來與Looper 溝通。Activity 等對象能夠藉由MyHandler 對象來將消息傳給Looper ,而後放入MessageQueue 裏;MyHandler 對象也扮演Listener 的角色,可接收Looper 對象所送來的消息。

 

[java]  view plain copy
 
  1. Message m = mHandler.obtainMessage(1, 1, 1, obj);  

 

先構造一個Message 對象,並將數據存入對象裏。

 

[java]  view plain copy
 
  1. mHandler.sendMessage(m);  

 

就透過mHandler 對象而將消息m 傳給Looper ,而後放入MessageQueue 裏。

此時,Looper 對象看到MessageQueue 裏有消息m ,就將它廣播出去,mHandler 對象接到此訊息時,會呼叫其handleMessage() 函數來處理,因而輸出"This my message!" 於畫面上

 

[java]  view plain copy
 
  1. public class Activity1 extends Activity implements OnClickListener{  
  2.        Button button = null ;  
  3.        TextView text = null ;  
  4.        @Override  
  5.        protected void onCreate(Bundle savedInstanceState) {  
  6.               super .onCreate(savedInstanceState);  
  7.               setContentView(R.layout.activity1 );          
  8.               button = (Button)findViewById(R.id.btn );  
  9.               button.setOnClickListener(this );  
  10.               text = (TextView)findViewById(R.id.content );  
  11.        }  
  12.        public void onClick(View v) {  
  13.               switch (v.getId()) {  
  14.               case R.id.btn :  
  15.                      Looper looper = Looper.myLooper();//取得當前線程裏的looper  
  16.                      MyHandler mHandler = new MyHandler(looper);//構造一個handler使之可與looper通訊  
  17.                      //buton等組件能夠由mHandler將消息傳給looper後,再放入messageQueue中,  
  18.              //同時mHandler也能夠接受來自looper消息  
  19.                      mHandler.removeMessages(0);  
  20.                      String msgStr = "主線程不一樣組件通訊:消息來自button";  
  21.                      Message m = mHandler.obtainMessage(1, 1, 1, msgStr);//構造要傳遞的消息  
  22.                      mHandler.sendMessage(m);//發送消息:系統會自動調用handleMessage方法來處理消息  
  23.                      break ;  
  24.                }              
  25.        }       
  26.        private class MyHandler extends Handler{               
  27.               public MyHandler(Looper looper){  
  28.                      super (looper);  
  29.               }  
  30.               @Override  
  31.               public void handleMessage(Message msg) {//處理消息  
  32.                      text.setText(msg.obj.toString());  
  33.               }              
  34.        }  
  35. }  

 

 

2、Android消息機制二

 

角色綜述(回顧)

   

1. UI thread 一般就是main thread ,而Android 啓動程序時會替它創建一個MessageQueue 。

2. 固然須要一個Looper 對象,來管理該MessageQueue 。

3. 咱們能夠構造Handler 對象來push 新消息到Message Queue 裏;或者接收Looper( 從Message Queue取出) 所送來的消息。

4. 線程A 的Handler 對象能夠傳遞給別的線程,讓別的線程B 或C 等能送訊息來給線程A( 存於A 的Message Queue 裏) 。

5. 線程A 的Message Queue 裏的消息,只有線程A 所屬的對象能夠處理。

 

子線程傳遞消息給主線程

舉例

[java]  view plain copy
 
  1. public class Activity2 extends Activity implements OnClickListener{  
  2.        Button button = null ;  
  3.        TextView text = null ;  
  4.        MyHandler mHandler = null ;  
  5.        Thread thread ;  
  6.        @Override  
  7.        protected void onCreate(Bundle savedInstanceState) {  
  8.               super .onCreate(savedInstanceState);  
  9.               setContentView(R.layout.activity1 );          
  10.               button = (Button)findViewById(R.id.btn );  
  11.               button.setOnClickListener(this );  
  12.               text = (TextView)findViewById(R.id.content );  
  13.        }  
  14.        public void onClick(View v) {  
  15.               switch (v.getId()) {  
  16.               case R.id.btn :  
  17.                      thread = new MyThread();  
  18.                      thread.start();  
  19.                      break ;  
  20.               }              
  21.        }       
  22.        private class MyHandler extends Handler{               
  23.               public MyHandler(Looper looper){  
  24.                      super (looper);  
  25.               }  
  26.               @Override  
  27.               public void handleMessage(Message msg) {//處理消息  
  28.                      text.setText(msg.obj.toString());  
  29.               }              
  30.        }  
  31.        private class MyThread extends Thread{  
  32.               @Override  
  33.               public void run() {  
  34.                      Looper curLooper = Looper.myLooper();  
  35.                      Looper mainLooper = Looper.getMainLooper();  
  36.                      String msg ;  
  37.                      if (curLooper==null ){  
  38.                             mHandler = new MyHandler(mainLooper);  
  39.                             msg = "curLooper is null";  
  40.                      }else {  
  41.                             mHandler = new MyHandler(curLooper);  
  42.                             msg = "This is curLooper";  
  43.                      }  
  44.                      mHandler.removeMessages(0);  
  45.                      Message m = mHandler.obtainMessage(1, 1, 1, msg);  
  46.                      mHandler.sendMessage(m);  
  47.               }              
  48.        }  
  49. }  

 

說明:

Android 會自動替主線程創建Message Queue 。在這個子線程裏並無創建Message Queue 。因此,myLooper 值爲null ,而mainLooper 則指向主線程裏的Looper 。因而,執行到:

 

[java]  view plain copy
 
  1. mHandler = new MyHandler (mainLooper);  

 

mHandler 屬於主線程。

 

[java]  view plain copy
 
  1. mHandler.sendMessage(m);  

 

就將m 消息存入到主線程的Message Queue 裏。mainLooper 看到Message Queue 裏有訊息,就會做出處理,因而由主線程執行到mHandler 的handleMessage() 來處理消息。

3、用Android線程間通訊的Message機制

在Android 下面也有多線程 的概念,在C/C++中,子線程能夠是一個函數 ,通常都是一個帶有循環的函數,來處理某些數據 ,優先線程只是一個複雜的運算過程,因此可能不須要while循環,運算完成,函數結束,線程就銷燬。對於那些須要控制的線程,通常咱們都是和互斥鎖相互關聯,從而來控制線程的進度,通常咱們建立子線程,一種線程是很常見的,那就是帶有消息循環的線程。
消息循環是一個頗有用的線程方式,曾經本身用C在Linux下面實現一個消息循環的機制 ,往消息隊列裏添加數據,而後異步的等待消息的返回。當消息隊列爲空的時候就會掛起線程,等待新的消息的加入。這是一個很通用的機制。
在 Android,這裏的線程分爲有消息循環的線程和沒有消息循環的線程,有消息循環的線程通常都會有一個Looper,這個事android的新概念。我 們的主線程(UI線程)就是一個消息循環的線程。針對這種消息循環的機制,咱們引入一個新的機制Handle,咱們有消息循環,就要往消息循環裏面發送相 應的消息,自定義 消息通常都會有本身對應的處理,消息的發送和清除,消息的的處理,把這些都封裝在Handle裏面,注意Handle只是針對那些有Looper的線程,不論是UI線程仍是子線程,只要你有Looper,我就能夠往你的消息隊列裏面添加東西,並作相應的處理。
可是這裏還有一點,就是隻要是關於UI相關的東西,就不能放在子線程中,由於子線程是不能操做UI的,只能進行數據、系統 等其餘非UI的操做。
那麼什麼狀況下面咱們的子線程才能看作是一個有Looper的線程呢?咱們如何獲得它Looper的句柄呢?
Looper.myLooper();            //得到當前的Looper
Looper.getMainLooper () ;  //得到UI線程的Lopper

咱們看看Handle的初始化函數,若是沒有參數,那麼他就默認使用的是當前的Looper,若是有Looper參數,就是用對應的線程的Looper。
如 果一個線程中調用Looper.prepare(),那麼系統就會自動的爲該線程創建一個消息隊列,而後調用 Looper.loop();以後就進入了消息循環,這個以後就能夠發消息、取消息、和處理消息。這個如何發送消息和如何處理消息能夠再其餘的線程中經過 Handle來作,但前提是咱們的Hanle知道這個子線程的Looper,可是你若是不是在子線程運行 Looper.myLooper(),通常是得不到子線程的looper的。

 

[java]  view plain copy
 
  1. public void run() {  
  2. <span style="white-space:pre">  </span>synchronized (mLock) {  
  3.    <span style="white-space:pre">       </span>Looper.prepare();  
  4.       <span style="white-space:pre">        </span>//do something  
  5.         }  
  6.         Looper.loop();  
  7. }  

因此不少人都是這樣作的:我直接在子線程中新建handle,而後在子線程中發送消息,這樣的話就失去了咱們多線程的意義了。

 

 

[java]  view plain copy
 
  1. class myThread extends Thread{  
  2.              private EHandler mHandler ;  
  3.              public void run() {  
  4.                  Looper myLooper, mainLooper;  
  5.                  myLooper = Looper.myLooper ();  
  6.                 mainLooper = Looper.getMainLooper ();  
  7.                 String obj;  
  8.                 if (myLooper == null ){  
  9.                          mHandler = new EHandler(mainLooper);  
  10.                          obj = "current thread has no looper!" ;  
  11.                 }  
  12.                 else {  
  13.                      mHandler = new EHandler(myLooper);  
  14.                      obj = "This is from current thread." ;  
  15.                 }  
  16.                 mHandler .removeMessages(0);  
  17.                 Message m = mHandler .obtainMessage(1, 1, 1, obj);  
  18.                 mHandler .sendMessage(m);  
  19.              }  
  20.   }  


可讓其餘的線程來控制咱們的handle,能夠把 private EHandler mHandler ;放在外面,這樣咱們的發消息和處理消息均可以在外面來定義,這樣增長程序 代碼 的美觀,結構更加清晰。
對如任何的Handle,裏面必需要重載一個函數
public void handleMessage(Message msg)
這個函數就是咱們的消息處理,如何處理,這裏徹底取決於你,而後經過 obtainMessage和 sendMessage等來生成和發送消息, removeMessages(0)來清除消息隊列。Google 真是太智慧了,這種框架 的產生,咱們寫代碼更加輕鬆了。
有的時候,咱們的子線程想去改變UI了,這個時候千萬不要再子線程中去修改,得到UI線程的Looper,而後發送消息便可。
咱們看看Goole Music App的源代碼 。
在MediaPlaybackActivity.java 中,咱們能夠看一下再OnCreate中的有這樣的兩句:

[java]  view plain copy
 
  1. mAlbumArtWorker = new Worker("album art worker");  
  2. mAlbumArtHandler = new AlbumArtHandler(mAlbumArtWorker.getLooper());  

很 明顯這兩句,是構建了一個子線程。而且這個子線程仍是Looper的子線程,這裏很牛逼的使用了 mAlbumArtWorker.getLooper()這個函數,由於咱們知道,咱們可以獲得子線程的Looper的途徑只有一個:就是在子線程中調用 Looper.myLooper (),而且這個函數還要在咱們perpare以後調用才能獲得正確的Looper,可是他這裏用了一個這樣的什麼東東 getLooper,不知道它是如何實現的?
這裏有一個大概的思路,咱們在子線程的的prepare以後調用 myLooper ()這個方法,而後保存在一個成員變量中,這個getLooper就返回這個東西,可是這裏會碰到多線程的一個很突出的問題,同步。咱們在父線程中調用 mAlbumArtWorker.getLooper(),可是想要這個返回正確的looper就必需要求咱們的子線程運行了prepare,可是這個東 西實在子線程運行的,咱們如何保證呢?
咱們看Google是如何實現的?

 

 

[java]  view plain copy
 
  1. private class Worker implements Runnable {  
  2.         private final Object mLock = new Object();  
  3.         private Looper mLooper;  
  4.           
  5.         /** 
  6.          * Creates a worker thread with the given name. The thread 
  7.          * then runs a [email=%7B@link]{@link [/email] android.os.Looper}. 
  8.          * @param name A name for the new thread 
  9.          */  
  10.         Worker(String name) {  
  11.             Thread t = new Thread(null, this, name);  
  12.             t.setPriority(Thread.MIN_PRIORITY);  
  13.             t.start();  
  14.             synchronized (mLock) {  
  15.                 while (mLooper == null) {  
  16.                     try {  
  17.                         mLock.wait();  
  18.                     } catch (InterruptedException ex) {  
  19.                     }  
  20.                 }  
  21.             }  
  22.         }  
  23.           
  24.         public Looper getLooper() {  
  25.             return mLooper;  
  26.         }  
  27.           
  28.         public void run() {  
  29.             synchronized (mLock) {  
  30.                 Looper.prepare();  
  31.                 mLooper = Looper.myLooper();  
  32.                 mLock.notifyAll();  
  33.             }  
  34.             Looper.loop();  
  35.         }  
  36.           
  37.         public void quit() {  
  38.             mLooper.quit();  
  39.         }  
  40.     }  

我 們知道,一個線程類的構造函數是在主線程中完成的,因此在咱們的 Worker的構造函數中咱們創佳一個線程,而後讓這個線程運行,這一這個線程的建立是指定一個 Runnable,這裏就是咱們的Worker自己,在主線程調用 t.start();,這後,咱們子線程已經建立,而且開始執行work的run方法。而後下面的代碼很藝術:

[java]  view plain copy
 
  1. synchronized (mLock) {  
  2.                 while (mLooper == null) {  
  3.                     try {  
  4.                         mLock.wait();  
  5.                     } catch (InterruptedException ex) {  
  6.                     }  
  7.                 }  
  8.             }  


咱們開始等待咱們的子線程給mLooper賦值,若是不賦值咱們就繼續等,而後咱們的子線程在運行run方法以後,在給 mLooper賦值以後,通知worker夠着函數中的wait,而後咱們的構造函數才能完成,因此咱們說:

[java]  view plain copy
 
  1. mAlbumArtWorker = new Worker("album art worker");  

這句自己就是阻塞的,它建立了一個子線程,開啓了子線程,而且等待子線程給mLooper賦值,賦值完成以後,這個函數才返回,這樣才能保證咱們的子線程的Looper的獲取 絕對是正確的,這個構思頗有創意。值得借鑑。

 

 

4、Android中Handler的使用方法——在子線程中更新界面

 

本文主要介紹Android的Handler的使用方法。Handler能夠發送Messsage和Runnable對象到與其相關聯的線程的消息隊列。每一個Handler對象與建立它的線程相關聯,而且每一個Handler對象只能與一個線程相關聯。

1.    Handler通常有兩種用途:

1)執行計劃任務,你能夠再預約的實現執行某些任務,能夠模擬定時器。

2)線程間通訊。在Android的應用啓動時,會 建立一個主線程,主線程會建立一個消息隊列來處理各類消息。

當你建立子線程時,你能夠再你的子線程中拿到父線程中建立的Handler對象,就能夠經過該 對象向父線程的消息隊列發送消息了。因爲Android要求在UI線程中更新界面,所以,能夠經過該方法在其它線程中更新界面。 

◆ 經過Runnable在子線程中更新界面

1)在onCreate中建立Handler 

 

[java]  view plain copy
 
  1. public class HandlerTestApp extends Activity {   
  2.         Handler mHandler;   
  3.         TextView mText;   
  4.         /** Called when the activity is first created. */   
  5.        @Override   
  6.        public void onCreate(Bundle savedInstanceState) {   
  7.            super.onCreate(savedInstanceState);   
  8.            setContentView(R.layout.main);   
  9.            mHandler = new Handler();//建立Handler   
  10.            mText = (TextView) findViewById(R.id.text0);//一個TextView   
  11.        }   

2) 構建Runnable對象,在runnable中更新界面,此處,咱們修改了TextView的文字.此處須要說明的是,Runnable對象能夠再主線程中建立,也能夠再子線程中建立。咱們此處是在子線程中建立的。   

 

 

[java]  view plain copy
 
  1. Runnable mRunnable0 = new Runnable()   
  2.     {   
  3.                 @Override   
  4.                 public void run() {   
  5.                         mText.setText("This is Update from ohter thread, Mouse DOWN");   
  6.                 }   
  7.     };   

3)   建立子線程,在線程的run函數中,咱們向主線程的消息隊列發送了一個runnable來更新界面。

 

 

[java]  view plain copy
 
  1. private void updateUIByRunnable(){   
  2.           new Thread()    
  3.          {    
  4.                //Message msg = mHandler.obtainMessage();    
  5.               public void run()    
  6.              {   
  7.   
  8.                    //mText.setText("This is Update from ohter thread, Mouse DOWN");//這句將拋出異常   
  9.                    mHandler.post(mRunnable0);    
  10.              }    
  11.          }.start();  
  12.   
  13.      }  

◆ 用Message在子線程中來更新界面

 

用Message更新界面與Runnable更新界面相似,只是須要修改幾個地方。

1) 實現本身的Handler,對消息進行處理

 

[java]  view plain copy
 
  1. private class MyHandler extends Handler   
  2.     {   
  3.   
  4.         @Override   
  5.         public void handleMessage(Message msg) {   
  6.             super.handleMessage(msg);   
  7.             switch(msg.what)   
  8.             {   
  9.             case UPDATE ://在收到消息時,對界面進行更新   
  10.                 mText.setText("This update by message");   
  11.                 break;   
  12.             }   
  13.         }   
  14.     }  

2)  在新的線程中發送消息  

 

 

[java]  view plain copy
 
  1. private void updateByMessage()   
  2.     {   
  3.         //匿名對象   
  4.          new Thread()   
  5.          {   
  6.                 public void run()   
  7.                 {   
  8.                     //mText.setText("This is Update from ohter thread, Mouse DOWN");  
  9.   
  10.                     //UPDATE是一個本身定義的整數,表明了消息ID   
  11.                     Message msg = mHandler.obtainMessage(UPDATE);   
  12.                     mHandler.sendMessage(msg);   
  13.                 }   
  14.          }.start();   
  15.     }  

5、AsyncTask與handler

 

         AsyncTask實際上就是一個線程池,AsyncTask在代碼上比handler要輕量級別,而實際上要比handler更耗資源,由於AsyncTask底層是一個線程池!而Handler僅僅就是發送了一個消息隊列,連線程都沒有開。
可是,若是異步任務的數據特別龐大,AsyncTask這種線程池結構的優點就體現出來了。

         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只能被執行一次,不然屢次調用時將會出現異常

[java]  view plain copy
 
    1. <span style="font-size: 14px;">    package cn.com.chenzheng_java;   
    2.           
    3.     import android.os.AsyncTask;   
    4.     /** 
    5.      *  
    6.      * @author chenzheng_java 
    7.      * @description 異步任務AcyncTask示例 
    8.      *     
    9.      */   
    10.     public class MyAsyncTask extends AsyncTask<String, Integer, Object> {   
    11.           
    12.      /** 
    13.      * 該方法由ui線程進行調用,用戶能夠在這裏盡情的訪問ui組件。 
    14.      * 不少時候,咱們會在這裏顯示一個進度條啥的,以示後臺正在 
    15.      * 執行某項功能。 
    16.      */   
    17.      @Override   
    18.      protected void onPreExecute() {   
    19.      super.onPreExecute();   
    20.      }   
    21.           
    22.      /** 
    23.      * 該方法由後臺進程進行調用,進行主要的耗時的那些計算。 
    24.      * 該方法在onPreExecute方法以後進行調用。固然在執行過程當中 
    25.      * 咱們能夠每隔多少秒就調用一次publishProgress方法,更新 
    26.      * 進度信息 
    27.      */   
    28.      @Override   
    29.      protected Object doInBackground(String... params) {   
    30.      return null;   
    31.      }   
    32.           
    33.           
    34.      /** 
    35.      * doInBackground中調用了publishProgress以後,ui線程就會 
    36.      * 調用該方法。你能夠在這裏動態的改變進度條的進度,讓用戶知道 
    37.      * 當前的進度。 
    38.      */   
    39.      @Override   
    40.      protected void onProgressUpdate(Integer... values) {   
    41.      super.onProgressUpdate(values);   
    42.      }   
    43.           
    44.      /** 
    45.      * 當doInBackground執行完畢以後,由ui線程調用。能夠在這裏 
    46.      * 返回咱們計算的最終結果給用戶。 
    47.      */   
    48.      @Override   
    49.      protected void onPostExecute(Object result) {   
    50.      super.onPostExecute(result);   
    51.      }   
    52.     }   
    53. </span>  
相關文章
相關標籤/搜索