乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      淺析Android中的消息機制

       My鏡像站 2012-01-19
      1. public class MainActivity extends Activity implements View.OnClickListener {  
      2.       
      3.     private TextView stateText;  
      4.     private Button btn;  
      5.       
      6.     @Override  
      7.     public void onCreate(Bundle savedInstanceState) {  
      8.         super.onCreate(savedInstanceState);  
      9.         setContentView(R.layout.main);  
      10.         stateText = (TextView) findViewById(R.id.tv);  
      11.         btn = (Button) findViewById(R.id.btn);  
      12.           
      13.         btn.setOnClickListener(this);  
      14.     }  
      15.   
      16.     @Override  
      17.     public void onClick(View v) {  
      18.         new WorkThread().start();  
      19.     }  
      20.       
      21.     //工作線程  
      22.     private class WorkThread extends Thread {  
      23.         @Override  
      24.         public void run() {  
      25.             //......處理比較耗時的操作  
      26.               
      27.             //處理完成后改變狀態(tài)  
      28.             stateText.setText("completed");  
      29.         }  
      30.     }  
      31. }  

      這段代碼似乎看上去很正常,但是當你運行時就會發(fā)現(xiàn),它會報一個致命性的異常:

      1. ERROR/AndroidRuntime(421): FATAL EXCEPTION: Thread-8  
      2. ERROR/AndroidRuntime(421): android.view.ViewRoot$CalledFromWrongThreadException:   
      3. Only the original thread that created a view hierarchy can touch its views.  

      到底是怎么回事呢?原因在于,Android系統(tǒng)中的視圖組件并不是線程安全的,如果要更新視圖,必須在主線程中更新,不可以在子線程中執(zhí)行更新的操作。

      既然這樣,我們就在子線程中通知主線程,讓主線程做更新操作吧。那么,我們如何通知主線程呢?我們需要使用到Handler對象。

      我們稍微修改一下上面的代碼:

       

      1. public class MainActivity extends Activity implements View.OnClickListener {  
      2.       
      3.     private static final int COMPLETED = 0;  
      4.       
      5.     private TextView stateText;  
      6.     private Button btn;  
      7.       
      8.     private Handler handler = new Handler() {  
      9.         @Override  
      10.         public void handleMessage(Message msg) {  
      11.             if (msg.what == COMPLETED) {  
      12.                 stateText.setText("completed");  
      13.             }  
      14.         }  
      15.     };  
      16.       
      17.     @Override  
      18.     public void onCreate(Bundle savedInstanceState) {  
      19.         super.onCreate(savedInstanceState);  
      20.         setContentView(R.layout.main);  
      21.         stateText = (TextView) findViewById(R.id.tv);  
      22.         btn = (Button) findViewById(R.id.btn);  
      23.           
      24.         btn.setOnClickListener(this);  
      25.     }  
      26.   
      27.     @Override  
      28.     public void onClick(View v) {  
      29.         new WorkThread().start();  
      30.     }  
      31.       
      32.     //工作線程  
      33.     private class WorkThread extends Thread {  
      34.         @Override  
      35.         public void run() {  
      36.             //......處理比較耗時的操作  
      37.               
      38.             //處理完成后給handler發(fā)送消息  
      39.             Message msg = new Message();  
      40.             msg.what = COMPLETED;  
      41.             handler.sendMessage(msg);  
      42.         }  
      43.     }  
      44. }  

      通過上面這種方式,我們就可以解決線程安全的問題,把復雜的任務處理工作交給子線程去完成,然后子線程通過handler對象告知主線程,由主線程更新視圖,這個過程中消息機制起著重要的作用。

      下面,我們就來分析一下Android中的消息機制。

      熟悉Windows編程的朋友知道Windows程序是消息驅動的,并且有全局的消息循環(huán)系統(tǒng)。Google參考了Windows的消息循環(huán)機制, 也在Android系統(tǒng)中實現(xiàn)了消息循環(huán)機制。Android通過Looper、Handler來實現(xiàn)消息循環(huán)機制。Android的消息循環(huán)是針對線程 的,每個線程都可以有自己的消息隊列和消息循環(huán)。

      Android系統(tǒng)中的Looper負責管理線程的消息隊列和消息循環(huán)。通過Looper.myLooper()得到當前線程的Looper對象,通過Looper.getMainLooper()得到當前進程的主線程的Looper對象。

      前面提到,Android的消息隊列和消息循環(huán)都是針對具體線程的,一個線程可以存在一個消息隊列和消息循環(huán),特定線程的消息只能分發(fā)給本線程,不 能跨線程和跨進程通訊。但是創(chuàng)建的工作線程默認是沒有消息隊列和消息循環(huán)的,如果想讓工作線程具有消息隊列和消息循環(huán),就需要在線程中先調用 Looper.prepare()來創(chuàng)建消息隊列,然后調用Looper.loop()進入消息循環(huán)。下面是我們創(chuàng)建的工作線程:

      1. class WorkThread extends Thread {  
      2.       public Handler mHandler;  
      3.   
      4.       public void run() {  
      5.           Looper.prepare();  
      6.   
      7.           mHandler = new Handler() {  
      8.               public void handleMessage(Message msg) {  
      9.                   // 處理收到的消息  
      10.               }  
      11.           };  
      12.   
      13.           Looper.loop();  
      14.       }  
      15.   }  

      這樣一來,我們創(chuàng)建的工作線程就具有了消息處理機制了。

      那么,為什么前邊的示例中,我們怎么沒有看到Looper.prepare()和Looper.loop()的調用呢?原因在于,我們的Activity是一個UI線程,運行在主線程中,Android系統(tǒng)會在Activity啟動時為其創(chuàng)建一個消息隊列和消息循環(huán)。

      前面提到最多的是消息隊列(MessageQueue)和消息循環(huán)(Looper),但是我們看到每個消息處理的地方都有Handler的存在,它 是做什么的呢?Handler的作用是把消息加入特定的Looper所管理的消息隊列中,并分發(fā)和處理該消息隊列中的消息。構造Handler的時候可以 指定一個Looper對象,如果不指定則利用當前線程的Looper對象創(chuàng)建。下面是Handler的兩個構造方法:

      1. /** 
      2.      * Default constructor associates this handler with the queue for the 
      3.      * current thread. 
      4.      * 
      5.      * If there isn't one, this handler won't be able to receive messages. 
      6.      */  
      7.     public Handler() {  
      8.         if (FIND_POTENTIAL_LEAKS) {  
      9.             final Class<? extends Handler> klass = getClass();  
      10.             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  
      11.                     (klass.getModifiers() & Modifier.STATIC) == 0) {  
      12.                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  
      13.                     klass.getCanonicalName());  
      14.             }  
      15.         }  
      16.   
      17.         mLooper = Looper.myLooper();  
      18.         if (mLooper == null) {  
      19.             throw new RuntimeException(  
      20.                 "Can't create handler inside thread that has not called Looper.prepare()");  
      21.         }  
      22.         mQueue = mLooper.mQueue;  
      23.         mCallback = null;  
      24.     }  
      25.   
      26. /** 
      27.      * Use the provided queue instead of the default one. 
      28.      */  
      29.     public Handler(Looper looper) {  
      30.         mLooper = looper;  
      31.         mQueue = looper.mQueue;  
      32.         mCallback = null;  
      33.     }  

      下面是消息機制中幾個重要成員的關系圖:

      一個Activity中可以創(chuàng)建出多個工作線程,如果這些線程把他們消息放入Activity主線程的消息隊列中,那么消息就會在主線程中處理了。因為主線程一般負責視圖組件的更新操作,對于不是線程安全的視圖組件來說,這種方式能夠很好的實現(xiàn)視圖的更新。

      那么,子線程如何把消息放入主線程的消息隊列中呢?只要Handler對象以主線程的Looper創(chuàng)建,那么當調用Handler的 sendMessage方法,系統(tǒng)就會把消息主線程的消息隊列,并且將會在調用handleMessage方法時處理主線程消息隊列中的消息。

      對于子線程訪問主線程的Handler對象,你可能會問,多個子線程都訪問主線程的Handler對象,發(fā)送消息和處理消息的過程中會不會出現(xiàn)數(shù)據(jù) 的不一致呢?答案是Handler對象不會出現(xiàn)問題,因為Handler對象管理的Looper對象是線程安全的,不管是添加消息到消息隊列還是從消息隊 列中讀取消息都是同步保護的,所以不會出現(xiàn)數(shù)據(jù)不一致現(xiàn)象。

      深入理解Android消息處理機制對于應用程序開發(fā)非常重要,也可以讓我們對線程同步有更加深刻的認識,希望這篇文章可以對朋友們有所幫助。

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多