1. ??????? 復習 Message Queue 的角色
在上一篇里,介紹了 Android 的 Thread 、 Looper 、 Message Queue 和 Handler 四者間之關系。
先復習如下:
l ??? UI thread? 通常就是 main thread ,而 Android 啟動程序時 ( 即創建 Process 時 ) 會替它建立一個 Message Queue 。
l ??? 當然需要一個 Looper 對象,來管理該 Message Queue 。
l ??? 我們可以創建 Handler 對象來 push 新消息到 Message Queue 里;或者接收 Looper( 從 Message Queue 取出 ) 所送來的消息。
l ??? 線程 A 的 Handler 對象引用可以傳遞給別的線程,讓別的線程 B 或 C 等能發送消息來給線程 A( 存于 A 的 Message Queue 里 ) 。
l ??? 線程 A 的 Message Queue 里的消息,只有線程 A 所屬的對象可以處理之 。
?
? 了解了四者間之關系后,在本篇里,就能來思考如何讓主線程與子線程之間互相溝通了。包括, 子線程 push 消息到主線程的 Message Queue 里,并觸發主線程去執行某項工作 ( 即執行某個函數 ) 。
?
2.?? 由別的線程發送消息到主線程的 Message Queue( 續 )
??? ? 在上一篇文章里,使用如下程序片段:
// ? class ?ac01? extends ?Activity {
??????????// ………
?????????????? public ? void ?onClick(View v) {
????????????????????? switch (v.getId()){
????????????????????? case ?101:
??????????????????????????? t ?=? new ?myThread();
??????????????????????????? t .start();
?????????????????????????? break ;
????????????????????? case ?102:
??????????????????finish();
???????????????????????????????? break ;
?????????????????????}
???????????}
//------------------------------------------------------?????????????
class ?EHandler? extends ?Handler {
??????????????????? public ?EHandler(Looper looper) {
??????????????????????? super (looper);
???????????????????}
??????????????????? @Override
??????????????????? public ? void ?handleMessage(Message msg) {
?????????????????????? tv .setText((String)msg. obj );
???????????????}
???????????}
//------------------------------------------------------?????????????
class ?myThread? extends ?Thread{
???????????? private ?EHandler? mHandler ;
???????????? public ? void ?run() {
????????????????Looper myLooper, mainLooper;
????????????????myLooper = Looper. myLooper ();
????????????????mainLooper = Looper. getMainLooper ();
????????????????String obj;
???????????????? if (myLooper ==? null ){
??????????????????????? mHandler ?=? new ?EHandler(mainLooper);
???????????????????????obj =? "current thread has no looper!" ;
????????????????}
???????????????? else ?{
????????????????????? mHandler ?=? new ?EHandler(myLooper);
?????????????????????obj =? "This is from current thread." ;
????????????????}
???????????????? mHandler .removeMessages(0);
????????????????Message m =? mHandler .obtainMessage(1, 1, 1, obj);
???????????????? mHandler .sendMessage(m);
?????????????}
??}
}
??
這個 mHandler 定義于 myThread 類別里,而且由子線程執行指令: ?????? mHandler ?=? new ?EHandler(mainLooper);
來創建 EHandler 對象;但是這個 mHandler 確是屬于 main 線程的 ( 用來存取主線程的 MessageQueue) ,所以指令:
mHandler .sendMessage(m); 是將 m 丟到主線程的 MessageQueue 里。
此外,我們也可以將 mHandler 定義于 ac01 類別里。如下程序范例:
?
//----- Looper_03 范例 ?-----
public ? class ?ac01? extends ?Activity? implements ?OnClickListener {
???? private ? final ? int ? WC ?= LinearLayout.LayoutParams. WRAP_CONTENT ;
???? private ? final ? int ? FP ?= LinearLayout.LayoutParams. FILL_PARENT ;
???? public ?TextView? tv ;
???? private ?myThread? t ;
???? private ?Button? btn ,? btn2 ;
????EventHandler? h ;
????Context? ctx ;
???? public ? void ?onCreate(Bundle icicle) {
???????????? super .onCreate(icicle);
???????????? ctx ?=? this ;
????????????????LinearLayout layout =? new ?LinearLayout( this );
????????????????layout.setOrientation(LinearLayout. VERTICAL );
??????????????????????????????
???????????????? btn ?=? new ?Button( this );
???????????????? btn .setId(101);
???????????????? btn .setBackgroundResource(R.drawable. heart );
???????????????? btn .setText( "test looper" );
???????????????? btn .setOnClickListener( this );
????????????????LinearLayout.LayoutParams param =
???????????????????? new ?LinearLayout.LayoutParams(100,50);
????????????????param. topMargin ?= 10;
????????????????layout.addView( btn , param);
???????????????
???????????????? btn2 ?=? new ?Button( this );
???????????????? btn2 .setId(102);
???????????????? btn2 .setBackgroundResource(R.drawable. ok_blue );
???????????????? btn2 .setText( "exit" );
???????????????? btn2 .setOnClickListener( this );
????????????????layout.addView( btn2 , param);
???????????????
???????????????? tv ?=? new ?TextView( this );
???????????????? tv .setTextColor(Color. WHITE );
???????????????? tv .setText( "" );
????????????????LinearLayout.LayoutParams param2 =
??????????????????? new ?LinearLayout.LayoutParams( FP ,? WC );
????????????????param2. topMargin ?= 10;
????????????????layout.addView( tv , param2);
????????????????setContentView(layout);?????
???????????????}
?????????? public ? void ?onClick(View v) {
???????? switch (v.getId()){
???????? case ?101:
????????????? h ?=? new ?EventHandler(Looper. myLooper ());
????????????? t ?=? new ?myThread();
????????????? t .start();
????????????? break ;
???????? case ?102:
???????finish();
???????????? break ;
????????}
????}
//------------------------------------------------?????
public ? class ?EventHandler? extends ?Handler {
???????????? public ?EventHandler(Looper looper) {
????????????????? super (looper);
?????????????}
????????????? @Override
????????????? public ? void ?handleMessage(Message msg) {
??????????????????????((Activity) ctx ).setTitle((String)msg. obj );
?????????????}
??????????}
//------------------------------------------------------??????
class ?myThread? extends ?Thread{
????? public ? void ?run() {
????????????String obj =? "from myThread" ;
????????????Message m =? h .obtainMessage(1, 1, 1, obj);
???????????? h .sendMessage(m);
??????}
??}
}
//------------------------------------------------------
?
指令: h ?=? new ?EventHandler(Looper. myLooper ());
此 h 是屬于 main 線程的 ( 用來存取主線程的 MessageQueue) 。在 myThread 類別里的指令: h .sendMessage(m);
雖然是由子線程執行該指令,還是將 m 丟到主線程的 MessageQueue 里。于是,子線程所執行的 run() 函數,就順利將 m 丟給主線程 ( 的 Message Queue) ,并觸發了主線程去執行 handleMessage() 函數了。顯示出畫面如下:
?
? 圖 1??
?
上述的指令:
?
??????????myLooper = Looper. myLooper ();
??????????mainLooper = Looper. getMainLooper ();
????????????????………
?????????? mHandler ?=? new ?EHandler(mainLooper);
??????????????????………
?????????? mHandler ?=? new ?EHandler(myLooper);
????????????????????………
?
都 明顯地指明 mHandler 是負責存取哪一個線程的 Message Queue 。不過,有時候并不需要特別指明。例如上述的 onClick() 函數和 EventHandler 類別,可改寫為:
?
//----- Looper_03aa? 范例 ?-----
// ? class ?ac01? extends ?Activity {
??????????// ………
??????? public ? void ?onClick(View v) {
???????? switch (v.getId()){
???????? case ?101:
????????????? h ?=? new ?EventHandler();
????????????? t ?=? new ?myThread();
????????????? t .start();
????????????? break ;
???????? case ?102:
??????????????finish();
???????????? break ;
????????}
????}
//------------------------------------------------?????
public ? class ?EventHandler? extends ?Handler {
????????????? @Override
????????????? public ? void ?handleMessage(Message msg) {
??????????????????????((Activity) ctx ).setTitle((String)msg. obj );
?????????????}
??????????}
//------------------------------------------------------??????
class ?myThread? extends ?Thread{
????? public ? void ?run() {
????????????String obj =? "from myThread" ;
????????????Message m =? h .obtainMessage(1, 1, 1, obj);
???????????? h .sendMessage(m);
??????}
??}
}
?
指令: h ?=? new ?EventHandler();? 就等于: h = new EventHandler(Looper.myLooper());
它建立了當前線程 (Current Thread) 的 EventHandler 對象。于此,是由 main 線程執行此指令的,所以此 EventHandler 對象是用來存取 main 線程的 Message Queue 。
上述程序將 handleMessage() 定義于 EventHandler 類別內,也可以直接定義于 ac01 類別之內。于是上述程序,也相當于:
?
//----- Looper_03bb? 范例 ?-----
// ? class ?ac01? extends ?Activity {
??????????// ………
?????????? public ? void ?onClick(View v) {
???????? switch (v.getId()){
???????? case ?101:
????????????? h ?=? new ?Handler(){
????????????????? public ? void ?handleMessage(Message msg) {
??????????????????????((Activity) ctx ).setTitle((String)msg. obj );
?????????????}};
?????????????? t ?=? new ?myThread();
????????????? t .start();
????????????? break ;
???????? case ?102:
????????finish();
???????????? break ;
????????}
????}
//------------------------------------------------------??????
class ?myThread? extends ?Thread{
????? public ? void ?run() {
????????????String obj =? "from myThread..." ;
????????????Message m =? h .obtainMessage(1, 1, 1, obj);
???????????? h .sendMessage(m);
??????}
??}
}
?
其執行結果是一樣的。
?
轉自: http://www.android1.net/Topic.aspx?BoardID=11&TopicID=631
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
