小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

淺析Android中的消息機(jī)制

 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.             //......處理比較耗時(shí)的操作  
  26.               
  27.             //處理完成后改變狀態(tài)  
  28.             stateText.setText("completed");  
  29.         }  
  30.     }  
  31. }  

這段代碼似乎看上去很正常,但是當(dāng)你運(yùn)行時(shí)就會(huì)發(fā)現(xiàn),它會(huì)報(bào)一個(gè)致命性的異常:

  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í)行更新的操作。

既然這樣,我們就在子線程中通知主線程,讓主線程做更新操作吧。那么,我們?nèi)绾瓮ㄖ骶€程呢?我們需要使用到Handler對(duì)象。

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

 

  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.             //......處理比較耗時(shí)的操作  
  37.               
  38.             //處理完成后給handler發(fā)送消息  
  39.             Message msg = new Message();  
  40.             msg.what = COMPLETED;  
  41.             handler.sendMessage(msg);  
  42.         }  
  43.     }  
  44. }  

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

下面,我們就來(lái)分析一下Android中的消息機(jī)制。

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

Android系統(tǒng)中的Looper負(fù)責(zé)管理線程的消息隊(duì)列和消息循環(huán)。通過(guò)Looper.myLooper()得到當(dāng)前線程的Looper對(duì)象,通過(guò)Looper.getMainLooper()得到當(dāng)前進(jìn)程的主線程的Looper對(duì)象。

前面提到,Android的消息隊(duì)列和消息循環(huán)都是針對(duì)具體線程的,一個(gè)線程可以存在一個(gè)消息隊(duì)列和消息循環(huán),特定線程的消息只能分發(fā)給本線程,不 能跨線程和跨進(jìn)程通訊。但是創(chuàng)建的工作線程默認(rèn)是沒(méi)有消息隊(duì)列和消息循環(huán)的,如果想讓工作線程具有消息隊(duì)列和消息循環(huán),就需要在線程中先調(diào)用 Looper.prepare()來(lái)創(chuàng)建消息隊(duì)列,然后調(diào)用Looper.loop()進(jìn)入消息循環(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.   }  

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

那么,為什么前邊的示例中,我們?cè)趺礇](méi)有看到Looper.prepare()和Looper.loop()的調(diào)用呢?原因在于,我們的Activity是一個(gè)UI線程,運(yùn)行在主線程中,Android系統(tǒng)會(huì)在Activity啟動(dòng)時(shí)為其創(chuàng)建一個(gè)消息隊(duì)列和消息循環(huán)。

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

  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.     }  

下面是消息機(jī)制中幾個(gè)重要成員的關(guān)系圖:

一個(gè)Activity中可以創(chuàng)建出多個(gè)工作線程,如果這些線程把他們消息放入Activity主線程的消息隊(duì)列中,那么消息就會(huì)在主線程中處理了。因?yàn)橹骶€程一般負(fù)責(zé)視圖組件的更新操作,對(duì)于不是線程安全的視圖組件來(lái)說(shuō),這種方式能夠很好的實(shí)現(xiàn)視圖的更新。

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

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

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

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多