總結線程交互

  說到線程,大家都知道,可以當作android進程的一個輕量級的表現,只是不佔有空間和資源。在android中,有一個線程是我們最常接觸到的,當我們做的一個應用,在第一次進入的時候,進入第一個Activity的時候,android自身就會自動創建一個用於控制一些控件以及繪圖的MainUI線程,也就是我們說的activity主線程。

  說到這裏,就不得不提到一個概念,它就是消息隊列,由於activity 的主線程裏面已經給我們準備好了消息隊列,所以我們只需要在用的時候直接用就可以了,但在自己創建的子線程裏面卻不行,因爲子線程本身並沒有消息隊列這個東西,在我們做線程交互的時候,刷新主界面的時候,往往是通過Handle來完成的,這裏不得不提到另一個東東,它叫LOOP,當我們從子線程裏面,通過handle來發送一個消息出來之後,LOOP會把這個消息發送回到主線程裏面,然後通過消息隊列的方法,來處理這些消息,最終達成我們刷新主界面的效果。

  那如何在我們自己創建的子線程裏面實現消息隊列,很簡單,調用Looper.prepare(),那麼系統就會自動的爲該線程建立一個消息隊列,然後調用 Looper.loop();之後就進入了消息循環,這個之後就可以發消息、取消息、和處理消息。這個方法對於平常,我們自己一些用來控制線程交互的實現,非常有用,所以分享一下。

  說到這裏,可能大家時常會遇到一些handle之後,好像沒用的現象,這是因爲,handle之後,LOOP把消息傳到了消息隊列的尾部,這是沒有問題的,但是在處理端的時候,就有可能會出現阻塞的現象,所以,用handle來處理一些複雜的圖象更新的時候,有時候有出現一些不可靠的現象。但Handle本身有自己的優勢,就是使用簡單,易懂,而且對於一般應用來說,出錯的情況並不是很頻繁,所以使用也就特別多。

  有可能大家會問,什麼是可靠的呢,這裏就不得不提到另一個東西,叫AsyncTask,簡單來說,就是異步任務。 

  實現:

  1)  子類化AsyncTask
       2)  實現AsyncTask中定義的下面一個或幾個方法
         onPreExecute() 開始執行前的準備工作;
         doInBackground(Params...) 開始執行後臺處理,可以調用publishProgress方法來更新實時的任務進度;
         onProgressUpdate(Progress...)  在publishProgress方法被調用後,UI thread將調用這個方法從而在界面上展示任務的進展情況,例如通過一個進度條進行展示。
         onPostExecute(Result) 執行完成後的操作,傳送結果給UI 線程。

  注意:     1) AsyncTask的實例必須在UI thread中創建;
        2) AsyncTask.execute方法必須在UI thread中調用;

  3)該task只能被執行一次,否則多次調用時將會出現異常。而且是不能手動停止

下面是一個例子,AsyncTask_eoe

  1. package xiaohang.zhimeng;   
  2.   
  3. import android.app.Activity;   
  4. import android.os.AsyncTask;   
  5. import android.os.Bundle;   
  6. import android.os.Handler;   
  7. import android.os.Message;   
  8. import android.os.SystemClock;   
  9. import android.widget.TextView;   
  10. import android.widget.Toast;   
  11.   
  12. /**  
  13.  * 一個使用異步任務的例子。一般來說一個異步任務只執行一次,這個例子有點非主流,任務結束後會觸發下一次任務執行。  
  14.  * 由任務task在屏幕上打印數字,第一次任務執行由主Activity的onCreate觸發,每次任務結束後  
  15.  * 設定下一次觸發的時間,共執行5次。對於任務來說doInBackground()接收任務的參數params,並執行產生數字的動作,每一個數字  
  16.  * 產生後調用一次publishProgress()來更新UI,這個函數本身也是異步的只是用來發個消息調用完成後立即返回,  
  17.  * 而產生數字的動作在繼續進行。更新界面的操作在onProgressUpdate()中設定。 所有的on函數都由系統調用,不能用戶調用。  
  18.  * 代碼中使用Handler是爲了能觸發任務執行,android規定這種異步任務每次執行完就結束,若要重新執行需要new一個新的。  
  19.  * 異步任務只能在UI線程裏面創建和執行  
  20.  */  
  21. public class testAsync extends Activity {   
  22.     private final int MSG_TIMER = 10000;   
  23.     private TextView vText = null;   
  24.   
  25.     @Override  
  26.     protected void onCreate(Bundle savedInstanceState) {   
  27.         // TODO Auto-generated method stub   
  28.         super.onCreate(savedInstanceState);   
  29.         setContentView(R.layout.test);   
  30.         vText = (TextView) findViewById(R.id.TextView01);   
  31.         vText.setText("Num...");   
  32.   
  33.         new task().execute("->");   
  34.   
  35.     }   
  36.   
  37.     // 接收任務task發來的消息,觸發一個新的任務   
  38.     private final Handler handler = new Handler() {   
  39.   
  40.         @Override  
  41.         public void handleMessage(Message msg) {   
  42.             // TODO Auto-generated method stub   
  43.             super.handleMessage(msg);   
  44.             System.out.println("Handler name -----------> " + Thread.currentThread().getName());   
  45.             System.out.println("Handler id ------------> " + Thread.currentThread().getId());   
  46.             switch (msg.what) {   
  47.             case MSG_TIMER:   
  48.                 new task().execute("->");   
  49.                 break;   
  50.             }   
  51.         }   
  52.     };   
  53.   
  54.     // 任務執行次數   
  55.     private static int times = 1;   
  56.   
  57.     // AsyncTask<>的參數類型由用戶設定,這裏設爲三個String   
  58.     // 第一個String代表輸入到任務的參數類型,也即是doInBackground()的參數類型   
  59.     // 第二個String代表處理過程中的參數類型,也就是doInBackground()執行過程中的產出參數類型,通過publishProgress()發消息   
  60.     // 傳遞給onProgressUpdate()一般用來更新界面   
  61.     // 第三個String代表任務結束的產出類型,也就是doInBackground()的返回值類型,和onPostExecute()的參數類型   
  62.     private class task extends AsyncTask<String, String, String> {   
  63.            
  64.         // 後臺執行的耗時任務,接收參數並返回結果   
  65.         // 當onPostExecute()執行完,在後臺線程中被系統調用   
  66.         @Override  
  67.         protected String doInBackground(String... params) {   
  68.             System.out.println("doInBackground name -----> " + Thread.currentThread().getName());   
  69.             System.out.println("doInBackground  id -----> " + Thread.currentThread().getId());   
  70.             // TODO Auto-generated method stub   
  71.             // 在這裏產生數據,送給onProgressUpdate以更新界面   
  72.             String pre = params[0];   
  73.             System.out.println("pre is ----->" + pre);   
  74.   
  75.             for (int i = 0; i < 5; i++) {   
  76.                 System.out.println("note i am begin sleep ");   
  77.                 publishProgress(pre + i);   
  78.                        
  79.                    
  80.                 // 這裏是否需要停頓下   
  81.                 System.out.println("hua li de bu zhuo " + pre + i);   
  82.                 SystemClock.sleep(1000);   
  83.             }   
  84.   
  85.             return "任務結束";   
  86.         }   
  87.   
  88.         // 任務執行結束後,在UI線程中被系統調用   
  89.         // 一般用來顯示任務已經執行結束   
  90.         @Override  
  91.         protected void onPostExecute(String result) {   
  92.             // TODO Auto-generated method stub   
  93.             System.out.println("onPostExecute name --------> " + Thread.currentThread().getName());   
  94.             System.out.println("onPostExecute id --------> " + Thread.currentThread().getName());   
  95.             super.onPostExecute(result);   
  96.   
  97.             Toast.makeText(testAsync.this, result, Toast.LENGTH_SHORT).show();   
  98.   
  99.             // 任務執行5次後推出   
  100.             if (times > 5) {   
  101.                 return;   
  102.             }   
  103.   
  104.             // 設定下一次任務觸發時間   
  105.             Message msg = Message.obtain();   
  106.             msg.what = MSG_TIMER;    
  107.             handler.sendMessageDelayed(msg, 10000L);   
  108.         }   
  109.   
  110.         // 最先執行,在UI線程中被系統調用   
  111.         // 一般用來在UI中產生一個進度條   
  112.         @Override  
  113.         protected void onPreExecute() {   
  114.             // TODO Auto-generated method stub   
  115.             System.out.println("onPreExecute id -------> " + Thread.currentThread().getId());   
  116.             System.out.println("onPreExecute name -------> " + Thread.currentThread().getName() );   
  117.             super.onPreExecute();   
  118.             Toast.makeText(testAsync.this"開始執行第" + times + "次任務: " + this,   
  119.                     Toast.LENGTH_SHORT).show();   
  120.             times++;   
  121.         }   
  122.   
  123.         // 更新界面操作,在收到更新消息後,在UI線程中被系統調用   
  124.         @Override  
  125.         protected void onProgressUpdate(String... values) {   
  126.             // TODO Auto-generated method stub   
  127.             System.out.println("onProgressUpdate id ---------> " + Thread.currentThread().getId());   
  128.             System.out.println("onProgressUpdate name -------> " + Thread.currentThread().getName());   
  129.             super.onProgressUpdate(values);   
  130.             vText.append(values[0]);   
  131.         }   
  132.   
  133.     }   
  134.   
  135. }  

     這個例子,寫得很好,裏面寫了很多關於它的一些使用的方法,注意在使用execute(XXX)裏面的參數,就是對應到下面幾個方法裏面的參數,AsyncTask<Params, Progress, Result>,這個就是相應的映射的參數表。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章