Microsoft Word - 004_Android線程模式介紹.doc

Similar documents
建模与图形思考

用手機直接傳值不透過網頁連接, 來當作搖控器控制家電 ( 電視遙控器 ) 按下按鍵發送同時會回傳值來確定是否有送出 問題 :1. 應該是使用了太多 thread 導致在傳值上有問題 2. 一次按很多次按鈕沒辦法即時反應

Microsoft Word - GoF-ch06-8-AbsFactory-ok.doc

單步除錯 (1/10) 打開 Android Studio, 點選 Start a new Android Studio project 建立專案 Application name 輸入 BMI 點下 Next 2 P a g e

多媒體應用 13 新增專案並完成版面配置 <ExMusic01> <activity_main.xml> ImageView ID imgplay ImageView ID imgstop ImageView ID imgfront TextView ID txtsong TextView ID t

主程式 : public class Main3Activity extends AppCompatActivity { ListView listview; // 先整理資料來源,listitem.xml 需要傳入三種資料 : 圖片 狗狗名字 狗狗生日 // 狗狗圖片 int[] pic =new

詞 彙 表 編 號 詞 彙 描 述 1 預 約 人 資 料 中 文 姓 名 英 文 姓 名 身 份 證 字 號 預 約 人 電 話 性 別 2 付 款 資 料 信 用 卡 別 信 用 卡 號 信 用 卡 有 效 日 期 3 住 房 條 件 入 住 日 期 退 房 日 期 人 數 房 間 數 量 入

Dynamic Layout in Android

新・解きながら学ぶJava

書面

Android Service

res/layout 目录下的 main.xml 源码 : <?xml version="1.0" encoding="utf 8"?> <TabHost android:layout_height="fill_parent" xml

ShareText

Android Android Android SDK iv

Microsoft PowerPoint - ch6 [相容模式]

教育部補助資訊軟體人才培育先導計畫 100 年度課程發展專案計畫 實驗課程名稱 : IPC(Inter-Process Communication) 開發教師 : 張晉源老師 開發學生 : 林政揚 學校系所 : 樹德科技大學資訊工程學系

untitled

EJB-Programming-4-cn.doc

運算子多載 Operator Overloading

题目

mvc

Database_001

Microsoft Word - G3_BK_Ch06-8.doc

Microsoft Word - 01.DOC

0511-Android程式之GPS應用_專題週記4

ContextMenu

untitled

untitled

任務二 : 產生 20 個有炸彈的磚塊, 放在隨機的位置編輯 Block 類別的程式碼 import greenfoot.; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) Write a description of class

预览图 : (2) 在 SelectCity.java 中增加控件, 用于绑定 select_city 文件的 ListView, TextView,EditTest 等控件 代码和注释如下 :


untitled

untitled

雲端 Cloud Computing 技術指南 運算 應用 平台與架構 10/04/15 11:55:46 INFO 10/04/15 11:55:53 INFO 10/04/15 11:55:56 INFO 10/04/15 11:56:05 INFO 10/04/15 11:56:07 INFO

呼 喊 選 集 2 3 天 國 大 英 雄 基 督 徒 因 此 在 基 督 快 將 再 臨 的 前 夕, 思 想 施 洗 約 翰 的 道 路, 對 我 們 來 說, 是 具 有 時 代 意 義 的 施 洗 約 翰 其 人 工 作 需 要 人, 需 要 合 用 的 人 在 神 的 國 度 中, 祂 所

國家圖書館典藏電子全文

Microsoft Word - GoF-ch02-8-hook-ok.doc

<4D F736F F F696E74202D20332D322E432B2BC3E6CFF2B6D4CFF3B3CCD0F2C9E8BCC6A1AAD6D8D4D8A1A2BCCCB3D0A1A2B6E0CCACBACDBEDBBACF2E707074>

untitled

Android Fragment

(TestFailure) JUnit Framework AssertionFailedError JUnit Composite TestSuite Test TestSuite run() run() JUnit

Java

untitled

エスポラージュ株式会社 住所 : 東京都江東区大島 東急ドエルアルス大島 HP: ******************* * 关于 Java 测试试题 ******

Microsoft Word - 第1章 Android基本概念.docx

KillTest 质量更高 服务更好 学习资料 半年免费更新服务

1: public class MyOutputStream implements AutoCloseable { 3: public void close() throws IOException { 4: throw new IOException(); 5: } 6:

Android 开发教程

Microsoft Word - Prog1-981.docx

Microsoft PowerPoint - plan08.ppt

SDK 概要 使用 Maven 的用户可以从 Maven 库中搜索 "odps-sdk" 获取不同版本的 Java SDK: 包名 odps-sdk-core odps-sdk-commons odps-sdk-udf odps-sdk-mapred odps-sdk-graph 描述 ODPS 基

全国计算机技术与软件专业技术资格(水平)考试

Microsoft Word - 第5章.doc

BOOL EnumWindows(WNDENUMPROC lparam); lpenumfunc, LPARAM (Native Interface) PowerBuilder PowerBuilder PBNI 2

Microsoft PowerPoint - App與微控器整合.pptx

提问袁小兵:

Android 编程基础 Android 开发教程 & 笔记 1

Adobe® Flash® 的 Adobe® ActionScript® 3.0 程式設計

9, : Java 19., [4 ]. 3 Apla2Java Apla PAR,Apla2Java Apla Java.,Apla,,, 1. 1 Apla Apla A[J ] Get elem (set A) A J A B Intersection(set A,set B) A B A B

Microsoft PowerPoint - 14Threads.ppt

概述

建立Android新專案

<4D F736F F D20C8EDC9E82DCFC2CEE7CCE22D3039C9CF>

Microsoft PowerPoint - plan06.ppt

Microsoft Word - ch04三校.doc

《大话设计模式》第一章

RecyclerView and CardVew

前言 C# C# C# C C# C# C# C# C# microservices C# More Effective C# More Effective C# C# C# C# Effective C# 50 C# C# 7 Effective vii

威 福 髮 藝 店 桃 園 市 蘆 竹 區 中 山 里 福 祿 一 街 48 號 地 下 一 樓 50,000 獨 資 李 依 純 105/04/06 府 經 登 字 第 號 宏 品 餐 飲 桃 園 市 桃 園 區 信 光 里 民

電機工程系認可證照清單 /7/1

Microsoft Word - 02.目錄.doc

投影片 1

RunPC2_.doc


Transcription:

Android 線程模式简介 基礎概念進程與線程在 Android 框架裡, 一個應用套件 (Application Package) 通常含有多個 Java 類 (Class), 這些類可以在同一個進程 (Process) 裡執行 ; 也可以在不同的進程裡執行 基於 Linux 的安全限制, 以及進程的基本特性 ( 例如, 不同進程的位址空間是獨立的 ), 如果兩個類 ( 或其對象 ) 在同一個進程裏執行時, 兩者溝通方便也快速 但是, 當它們分別在不同的進程裡執行時, 兩者溝通就屬於 IPC 跨進程溝通了, 不如前者方便, 也慢些 一個進程是一個獨立的執行空間, 不會被正在其他進程裡的程序所侵犯 這種保護方法是 Android 的重要安全機制 於是, 得先認識進程的內涵, 才能進一步了解跨進程 IPC(Inter-Process Communication) 機制 在 Android 的進程裡, 有一個虛擬機 (Virtual Machine, 簡稱 VM) 的對象, 可執行 Java 代碼, 也引導 JNI 本地程序的執行, 實現 Java 與 C/C++ 程序之間的溝通 ; 如下圖 : 圖 1 Android 進程裡的基本元素

每一個進程在誕生時, 都會誕生一個主線程 (Main Thread), 以及誕生一個 Looper 類的對象和一個 MQ(Message Queue) 資料結構 每當主線程作完事情, 就會去執行 Looper 類 此時, 不斷地觀察 MQ 的動態 如下圖 : 圖 2 Android 內部含有多個進程 主線程最主要的工作就是處理 UI 畫面的事件 (Event), 每當 UI 事件發生時,Android 框架會丟信息 (Message) 到 MQ 裡 主線程看到 MQ 有新的信息時, 就取出信息, 然後依據信息內容而去執行特定的函數 執行完畢, 就再繼續執行 Looper 類, 不斷地觀察 MQ 的動態 大家都知道, 當兩個類都在同一個進程裡執行時, 兩者之間的溝通, 只要採取一般的函數調用 (Function Call) 就行了, 既快速又方便 一旦兩個類分別在不同的進程裡執行時, 兩者之間的溝通, 就不能採取一般的函數調用途徑了 只好採取 IPC 溝通途徑, 如下圖 :

IPC 圖 3 Android 框架的 IPC 機制之例 Android 框架的 IPC 溝通仰賴單一的 IBinder 接口 此時 Client 端調用 IBinder 接口的 transact() 函數, 透過 IPC 機制而調用到遠方 (Remote) 的 ontransact() 函數 例如下圖裡的 myactivity1 myactivity2 和 myservice 分別在不同的進程裡執行, 透過 C++ 層的 IBinder 接口進行跨進程的 IPC 溝通 圖 4 Android IPC 機制的 IBinder 接口

在此圖的不同進程裡, 各有其主線程 (Thread), 這些線程可並行 (Concurrent) 執行, 形成多線程 (Multiple-Thread) 的執行環境 例如上圖 4-14, myactivity1 和 myactivity2 並行執行, 並透過 C++ 層的 JavaBBinder 類而共享 ( 可能並行 ) 了 Java 層的 myservice 類之服務 認識主線程在 Android 裏, 於預設情形下, 一個應用程式內的各元件 ( 如 Activity BroadcastReceiver 或 Service 等 ) 都會在同一個進程 (Process) 裏執行, 而且由該進程的主線程負責執行之 在 Android 裏, 如果有特別指示, 也可以讓特定元件在不同的進程裏執行 無論元件在那一個進程裏執行, 於預設情形下, 他們都是由該進程裏的主線程來負責執行之 例如下述的範例, 由一個 Activity 啟動一個 Service, 兩者都在同一個進程裏執行 那麼, 主線程除了要處理 Activity 元件的 UI 事件, 又要處理 Service 幕後服務工作, 通常會忙不過來 該如何化解這種困境呢? 此時, 多線程 (Multi-thread) 的並行 (Concurrent) 概念了, 其可以化解主線程太過於忙碌的情形 也就是說, 主線程可以誕生多個子線程來分擔其工作, 尤其是比較冗長費時的幕後服務工作, 例如播放動畫的背景音樂 或從網路下載映片等 於是, 主線程就能專心於處理 UI 畫面的事件了 關於 Remote Service 剛才的範例裏的 Activity Service 和 BroadcastReceiver 三者都是由該 APK 的預設進程裏執行 由於三者都是在同一進程裏執行, 所以它們之間的通訊是屬於進程內的短距通訊 同時, 也都由該預設進程裏的主線程負責執行之 那麼, 如果 Activity Service 和 BroadcastReceiver 三者並不是在同一個進程裏執行時, 它們之間的通訊就是跨進程通訊 (IPC, Inter-Process Communication) 了 當 Activity 與 Service( 或 BroadcastReceiver) 之間採用 IPC 通訊時, 意味著兩者分別在不同的進程裏執行, 此時基於一般原則 : 於預設情形下,Activity BroadcastReceiver 或 Service 都是由其所屬進程裏的主線程負責執行之 可知, 雙方是分別由不同 ( 進程 ) 的主線程來執行之 請先看個範例, 它由一個 Activity 啟動一個遠距的 Service, 兩者分別在不同的進程裏執行 如下述 XML 檔案內容 : <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.misoo.kxaa"> <application android:icon="@drawable/icon"> <activity android:name=".ac01" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> <service android:name=".myservice" android:process=":remote"> <intent-filter> <action android:name="com.misoo.kxaa.remote_service" /> </intent-filter> </service> </application> </manifest> 從其中可看到,ac01 是在此應用程式的預設進程裏執行的, 而 myservice 是在名為 remote 的進程裏執行的 所以 ac01 是由該預設進程的主線程所執行的, 而 myservice 則是由 remote 進程的主線程所執行的 此應用程式共含有兩個進程 : 預設進程和 remote 進程 請繼續看下圖 : 其中,myActivity 與 myservice 各在不同進程裏執行, 兩者都是由各進程的 main thread 所執行 亦即, 兩者是由不同的線程所執行 此情形下, 兩個類別裏的函數也不宜太費時 ( 例如不宜超過 5 秒鐘 ); 但必要時可誕生子線程去執行較費時的函數 由於 new mybinder() 指令寫在 myservice::oncreate() 內, 所以是由 main thread 執行建構式 mybinder() 在 Binding-time 時,Binder System 會從進程的線程池 (Thread pool) 裏啟動一個線程來執行 mybinder::ontransact() 函數 以此類推, 下圖的 mybinder1::ontransact() 與 mybinder1::ontransact() 兩個函數, 是由不同的線程分別執行之

就 Android 的 Java 層應用程式開發者而言, 他們可能不會太重視上述的線程機制 然而, 對於軟硬整合元件開發者而言, 就非常重要了 結語 Binding-time 時,Binder System 會建立 myactivity 與 mybinder( 即 myservice 的 Interface) 之間的連結 (Connection) 在 IPC calling-time 時, 每次 IPC call,binder System 會從 Service 進程的 Thread pool 裏啟動一個 Thread 來對應 myactivity 的線程 在 Binding-time 時,Binder System 會建立 myactivity 與 mybinder( 即 myservice 的 Interface) 之間的連結 (Connection) 在 IPC calling-time 時,myActivity 的線程與 mybinder 的線程會同步 (Synchronize), 讓 myactivity 開發者覺得 IPC 遠端呼叫 跨進程的兩個線程, 就如同單一線程一般 如下圖 : 如果從 Binder 衍生了 mybinder1 mybinder2 和 mybinder3 等子類時, 如何替 myservice 選擇適當的 mybinder 介面類別呢? 如果連續呼叫 bindservice() 兩次, 會 bind 到同一個 mybinder 物件

如果想 Bind 到另一個 mybinder 介面類別之物件, 可先 unbind(), 就會呼叫到 onbind() 函數, 來決定 bind 到哪一個物件 其他還有更多變化的結構, 如下圖 : 主 子線程的通訊模式 Message Queue 的角色 在 Android 程式裏, 新誕生一個線程, 或稱執行緒 (Thread) 時, 並不會自動建立其 Message Loop Android 裏並沒有 Global 的 Message Queue 資料結構, 例如, 不同 APK 裏的物件不能透過 Massage Queue 來交換訊息 (Message) 一個線程可以誕生一個 Looper 之物件, 由它來管理此線程裏的 Message Queue 你可以誕生 Handler 之物件來與 Looper 溝通, 以便 push 新訊息到 Message Queue 裏 ; 或者接收 Looper( 從 Message Queue 取出 ) 所送來的訊息 線程 A 的 Handler 物件參考可以傳遞給別的線程, 讓別的線程 B 或 C 等能送訊息來給線程 A( 存於 A 的 Message Queue 裏 ) 線程 A 的 Message Queue 裏的訊息, 只有線程 A 所屬的物件可以處理之 使用 Looper.myLooper 可以取得目前線程的 Looper 物件參考值 使用 mhandler = new EevntHandler(Looper.myLooper()); 可誕生用來處理目前線程的 Handler 物件 ; 其中,EevntHandler 是 Handler 的子類別 使用 mhandler = new EevntHandler(Looper.getMainLooper()); 可誕生用來處

理 main 線程的 Handler 物件 ; 其中,EevntHandler 是 Handler 的子類別 範例之一 :Looper 物件之角色 Looper 類別用來管理特定線程內物件之間的訊息交換 (Message Exchange) 你的應用程式可以誕生許多個線程, 或稱執行緒 (Thread) 而一個線程可以誕生許多個物件, 這些物件之間常常需要互相交換訊息 如果有這種需要, 您可以替線程誕生一個 Looper 類別之物件, 來擔任訊息交換的管理工作 Looper 物件會建立一個 MessageQueue 資料結構來存放各物件傳來的訊息 ( 包括 UI 事件或 System 事件等 ) 如下圖: Activity Looper IntentReceiver MessageQueue Thread 每一個線程 (Thread, 或稱 執行緒 ) 裏可含有一個 Looper 物件以及一個 MessageQueue 資料結構 在你的應用程式裏, 可以定義 Handler 的子類別來接收 Looper 所送出的訊息 //----- Looper_01 範例 ----- package com.misoo.kx04; import android.app.activity; import android.graphics.color; import android.os.bundle; import android.os.handler; import android.os.looper; import android.os.message; import android.view.view; import android.view.view.onclicklistener; import android.widget.button; import android.widget.linearlayout; import android.widget.textview; 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 EventHandler mhandler;

private Button btn, btn2, btn3; public void oncreate(bundle icicle) { super.oncreate(icicle); 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: Looper looper; looper = Looper.myLooper(); mhandler = new EventHandler(looper); mhandler.removemessages(0); // 清除整個 MessageQueue 裏的事件, 確保不會通知到別人 String obj = "This my message!"; Message m = mhandler.obtainmessage(1, 1, 1, obj); // 組裝成一個 Message 物件 mhandler.sendmessage(m); // 將 Message 物件送入 MessageQueue 裏 break; case 102: finish(); break;

//------------------------------------------------------ class EventHandler extends Handler { public EventHandler(Looper looper) { super(looper); @Override public void handlemessage(message msg) { tv.settext((string)msg.obj); 說明此程式啟動時, 目前線程 ( 即主線程, main thread) 已誕生了一個 Looper 物件, 並且有了一個 MessageQueue 資料結構 指令 :looper = Looper.myLooper(); 就呼叫 Looper 類別的靜態 mylooper() 函數, 以取得目前線程裏的 Looper 對象之參考值 指令 :mhandler = new EventHandler(looper); 誕生一個 EventHandler 之物件來與 Looper 溝通 Activity 等物件可以藉由 EventHandler 物件來將訊息傳給 Looper, 然後放入 MessageQueue 裏 ;EventHandler 物件也扮演 Listener 的角色, 可接收 Looper 物件所送來的訊息 如下圖 : Activity EHandler Looper IntentReceiver EHandler MessageQueue Thread 指令 :Message m = mhandler.obtainmessage(1, 1, 1, obj); 先誕生一個 Message 物件, 並將資料存入次物件裏

指令 :mhandler.sendmessage(m); 就透過 mhandler 物件而將訊息 m 傳給 Looper, 然後放入 MessageQueue 裏 此時,Looper 物件看到 MessageQueue 裏有訊息 m, 就將它廣播出去,mHandler 物件接到此訊息時, 會呼叫其 handlemessage() 函數來處理之, 於是輸出 "This my message!" 於畫面上, 如下 : 範例之二 : 由別的線程送訊息到主線程的 Message Queue //----- Looper_02 範例 ----- package com.misoo.kx04; import android.app.activity; import android.graphics.color; import android.os.bundle; import android.os.handler; import android.os.looper; import android.os.message; import android.view.view; import android.view.view.onclicklistener; import android.widget.button; import android.widget.linearlayout; import android.widget.textview; 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, btn3; public void oncreate(bundle icicle) { super.oncreate(icicle); 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: 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); Android 會自動替主線程建立 Message Queue 在這個子線程裏並沒有建立 Message Queue 所以,myLooper 值為 null, 而 mainlooper 則指向主線程裏的 Looper 物件 於是, 執行到指令 : mhandler = new EHandler(mainLooper); 此 mhandler 屬於主線程 指令 :mhandler.sendmessage(m); 就將 m 訊息存入到主線程的 Message Queue 裏 mainlooper 看到 Message Queue 裏有訊息, 就會處理之, 於是由主線程執行到 mhandler 的 handlemessage() 函數來處理訊息 由主線程送訊息給子線程上述範例裏, 是由子線程丟訊息給主線程 本節將介紹如何從主線程丟訊息給子線程 其方法是 : 當子線程執行 run() 函數時, 就誕生一個子線程的 Handler 物件 之後, 當主線程執行 ac01::onclick() 函數時, 就藉由此 Handler 物件參考而 push 訊息給子線程 例如下述範例 : //----- Looper_04 範例 ----- package com.misoo.kx04; import android.app.activity; import android.content.context; import android.graphics.color; import android.os.bundle; import android.os.handler; import android.os.looper;

import android.os.message; import android.view.view; import android.view.view.onclicklistener; import android.widget.button; import android.widget.linearlayout; import android.widget.textview; 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; private Handler h; private 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); //------------------------ t = new mythread(); t.start();

public void onclick(view v) { switch(v.getid()){ case 101: String obj = "mainthread"; Message m = h.obtainmessage(1, 1, 1, obj); h.sendmessage(m); break; case 102: h.getlooper().quit(); 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() { Looper.prepare(); h = new Handler(){ public void handlemessage(message msg) { EventHandler ha = new EventHandler(Looper.getMainLooper()); String obj = (String)msg.obj + ", mythread"; Message m = ha.obtainmessage(1, 1, 1, obj); ha.sendmessage(m); ; Looper.loop(); 當子線程執行 run() 函數時, 誕生一個主線程的 EventHandler 物件, 並且藉之而 push 訊息給主線程了 就進行了兩個線程之間的互相交換訊息, 也是兩個函數或物件間之交換訊息 此程式輸出畫面為 :

~~ END ~~