1.1.Message
代碼在frameworks\base\core\java\android\Os\Message.java中。
Message.obtain函數:有多個obtain函數,主要功能一樣,隻是參數不一樣。作用是從Message Pool中取出一個Message,如果Message Pool中已經沒有Message可取則新建一個Message返回,同時用對應的參數給得到的Message對象賦值。
Message Pool:大小為10個;通過Message.mPool->(Message並且Message.next)->(Message並且Message.next)->(Message並且Message.next)…構造一個Message Pool。Message Pool的第一個元素直接new出來,然後把Message.mPool(static類的static變量)指向它。其他的元素都是使用完的 Message通過Message的recycle函數清理後放到Message Pool(通過Message Pool最後一個Message的next指向需要回收的Message的方式實現)。下圖為Message Pool的結構:
1.2.MessageQueue
MessageQueue裡面有一個收到的Message的對列:
MessageQueue.mMessages(static變量)->( Message並且Message.next)-> ( Message並且Message.next)->…,下圖為接收消息的消息隊列:
上層代碼通過Handler的sendMessage等函數放入一個message到MessageQueue裡面時最終會調用MessageQueue的 enqueueMessage函數。enqueueMessage根據上面的接收的Message的隊列的構造把接收到的Message放入隊列中。
MessageQueue的removeMessages函數根據上面的接收的Message的隊列的構造把接收到的Message從隊列中刪除,並且調用對應Message對象的recycle函數把不用的Message放入Message Pool中。
1.3.Looper
Looper對象的創建是通過prepare函數,而且每一個Looper對象會和一個線程關聯
Java代碼
1. public static final void prepare() {
2. if (sThreadLocal.get() != null) {
3. throw new RuntimeException("Only one Looper may be created per thread");
4. }
5. sThreadLocal.set(new Looper());
6. }
Looper對象創建時會創建一個MessageQueue,主線程默認會創建一個Looper從而有MessageQueue,其他線程默認是沒有 MessageQueue的不能接收Message,如果需要接收Message則需要通過prepare函數創建一個MessageQueue。具體操作請見示例代碼。
Java代碼
1. private Looper() {
2. mQueue = new MessageQueue();
3. mRun = true;
4. mThread = Thread.currentThread();
5. }
prepareMainLooper函數隻給主線程調用(系統處理,程序員不用處理),它會調用prepare建立Looper對象和MessageQueue。
Java代碼
1. public static final void prepareMainLooper() {
2. prepare();
3. setMainLooper(myLooper());
4. if (Process.supportsProcesses()) {
5. myLooper().mQueue.mQuitAllowed = false;
6. }
7. }
Loop函數從MessageQueue中從前往後取出Message,然後通過Handler的dispatchMessage函數進行消息的處理(可見消息的處理是Handler負責的),消息處理完瞭以後通過Message對象的recycle函數放到Message Pool中,以便下次使用,通過Pool的處理提供瞭一定的內存管理從而加速消息對象的獲取。至於需要定時處理的消息如何做到定時處理,請見 MessageQueue的next函數,它在取Message來進行處理時通過判斷MessageQueue裡面的Message是否符合時間要求來決定是否需要把Message取出來做處理,通過這種方式做到消息的定時處理。
Java代碼
1. public static final void loop() {
2. Looper me = myLooper();
3. MessageQueue queue = me.mQueue;
4. while (true) {
5. Message msg = queue.next(); // might block
6. //if (!me.mRun) {
7. // break;
8. //}
9. if (msg != null) {
10. if (msg.target == null) {
11. // No target is a magic identifier for the quit message
12. return;
13. }
14.
15. if (me.mLogging!= null)
16. me.mLogging.println(">>>>> Dispatching to " + msg.target + " "+ msg.callback + ": " + msg.what);
17. msg.target.dispatchMessage(msg);
18. if (me.mLogging!= null)
19. me.mLogging.println("<<<<< Finished to" + msg.target + " "+ msg.callback);
20. msg.recycle();
21. }
22. }
23. }
1.4.Handler
Handler的構造函數表示Handler會有成員變量指向Looper和MessageQueue,後面我們會看到沒什麼需要這些引用;至於callback是實現瞭Callback接口的對象,後面會看到這個對象的作用。
Java代碼
1. public Handler(Looper looper, Callback callback) {
2. mLooper = looper;
3. mQueue = looper.mQueue;
4. mCallback = callback;
5. }
6.
7. public interface Callback {
8. public boolean handleMessage(Message msg);
9. }
獲取消息:直接通過Message的obtain方法獲取一個Message對象。
Java代碼
1. public final Message obtainMessage(int what, int arg1, int arg2, Object obj){
2. return Message.obtain(this, what, arg1, arg2, obj);
3. }
發送消息:通過MessageQueue的enqueueMessage把Message對象放到MessageQueue的接收消息隊列中
Java代碼
1. public boolean sendMessageAtTime(Message msg, long uptimeMillis){
2. boolean sent = false;
3. MessageQueue queue = mQueue;
4. if (queue != null) {
5. msg.target = this;
6. sent = queue.enqueueMessage(msg, uptimeMillis);
7. } else {
8. RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");
9. Log.w("Looper", e.getMessage(), e);
10. }
11. return sent;
12. }
線程如何處理MessageQueue中接收的消息:在Looper的loop函數中循環取出MessageQueue的接收消息隊列中的消息,然後調用 Hander的dispatchMessage函數對消息進行處理,至於如何處理(相應消息)則由用戶指定(三個方法,優先級從高到低:Message裡面的Callback,一個實現瞭Runnable接口的對象,其中run函數做處理工作;Handler裡面的mCallback指向的一個實現瞭 Callback接口的對象,裡面的handleMessage進行處理;處理消息Handler對象對應的類繼承並實現瞭其中 handleMessage函數,通過這個實現的handleMessage函數處理消息)。
Java代碼
1. public void dispatchMessage(Message msg) {
2. if (msg.callback != null) {
3. handleCallback(msg);
4. } else {
5. if (mCallback != null) {
6. if (mCallback.handleMessage(msg)) {
7. return;
8. }
9. }
10. handleMessage(msg);
11. }
12. }
Runnable說明:Runnable隻是一個接口,實現瞭這個接口的類對應的對象也隻是個普通的對象,並不是一個Java中的Thread。Thread類經常使用Runnable,很多人有誤解,所以這裡澄清一下。
從上可知以下關系圖:
其中清理Message是Looper裡面的loop函數指把處理過的Message放到Message的Pool裡面去,如果裡面已經超過最大值10個,則丟棄這個Message對象。
調用Handler是指Looper裡面的loop函數從MessageQueue的接收消息隊列裡面取出消息,然後根據消息指向的Handler對象調用其對應的處理方法。
1.5.代碼示例
下面我們會以android實例來展示對應的功能,程序界面於下:
程序代碼如下,後面部分有代碼說明:
Java代碼
1. package com.android.messageexample;
2. import android.app.Activity;
3. import android.content.Context;
4. import android.graphics.Color;
5. import android.os.Bundle;
6. import android.os.Handler;
7. import android.os.Looper;
8. import android.os.Message;
9. import android.util.Log;
10. import android.view.View;
11. import android.view.View.OnClickListener;
12. import android.widget.Button;
13. import android.widget.LinearLayout;
14. import android.widget.TextView;
15. public class MessageExample extends Activity implements OnClickListener {
16. private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT;
17. private final int FP = LinearLayout.LayoutParams.FILL_PARENT;
18. public TextView tv;
19. private EventHandler mHandler;
20. private Handler mOtherThreadHandler=null;
21. private Button btn, btn2, btn3, btn4, btn5, btn6;
22. private NoLooperThread noLooerThread = null;
23. private OwnLooperThread ownLooperThread = null;
24. private ReceiveMessageThread receiveMessageThread =null;
25. private Context context = null;
26. private final String sTag = "MessageExample";
27. private boolean postRunnable = false;
28.
29. /** Called when the activity is first created. */
30. @Override
31. public void onCreate(Bundle savedInstanceState) {
32. super.onCreate(savedInstanceState);
33. context = this.getApplicationContext();
34. LinearLayout layout = new LinearLayout(this);
35. layout.setOrientation(LinearLayout.VERTICAL);
36. btn = new Button(this);
37. btn.setId(101);
38. btn.setText("message from main thread self");
39. btn.setOnClickListener(this);
40. LinearLayout.LayoutParams param =
41. new LinearLayout.LayoutParams(250,50);
42. param.topMargin = 10;
43. layout.addView(btn, param);
44. btn2 = new Button(this);
45. btn2.setId(102);
46. btn2.setText("message from other thread to main thread");
47. btn2.setOnClickListener(this);
48. layout.addView(btn2, param);
49. btn3 = new Button(this);
50. btn3.setId(103);
51. btn3.setText("message to other thread from itself");
52. btn3.setOnClickListener(this);
53. layout.addView(btn3, param);
54. btn4 = new Button(this);
55. btn4.setId(104);
56. btn4.setText("message with Runnable as callback from other thread to main thread");
57. btn4.setOnClickListener(this);
58. layout.addView(btn4, param);
59. btn5 = new Button(this);
60. btn5.setId(105);
61. btn5.setText("main thread's message to other thread");
62. btn5.setOnClickListener(this);
63. layout.addView(btn5, param);
64. btn6 = new Button(this);
65. btn6.setId(106);
66. btn6.setText("exit");
67. btn6.setOnClickListener(this);
68. layout.addView(btn6, param);
69. tv = new TextView(this);
70. tv.setTextColor(Color.WHITE);
71. tv.setText("");
72. LinearLayout.LayoutParams param2 =
73. new LinearLayout.LayoutParams(FP, WC);
74. param2.topMargin = 10;
75. layout.addView(tv, param2);
76. setContentView(layout);
77.
78. //主線程要發送消息給other thread, 這裡創建那個other thread
79. receiveMessageThread = new ReceiveMessageThread();
80. receiveMessageThread.start();
81. }
82.
83. //implement the OnClickListener interface
84. @Override
85. public void onClick(View v) {
86. switch(v.getId()){
87. case 101:
88. //主線程發送消息給自己
89. Looper looper;
90. looper = Looper.myLooper(); //get the Main looper related with the main thread
91. //如果不給任何參數的話會用當前線程對應的Looper(這裡就是Main Looper)為Handler裡面的成員mLooper賦值
92. mHandler = new EventHandler(looper);
93. //mHandler = new EventHandler();
94. // 清除整個MessageQueue裡的消息
95. mHandler.removeMessages(0);
96. String obj = "This main thread's message and received by itself!";
97. //得到Message對象
98. Message m = mHandler.obtainMessage(1, 1, 1, obj);
99. // 將Message對象送入到main thread的MessageQueue裡面
100. mHandler.sendMessage(m);
101. break;
102. case 102:
103. //other線程發送消息給主線程
104. postRunnable = false;
105. noLooerThread = new NoLooperThread();
106. noLooerThread.start();
107. break;
108. case 103:
109. //other thread獲取它自己發送的消息
110. tv.setText("please look at the error level log for other thread received message");
111. ownLooperThread = new OwnLooperThread();
112. ownLooperThread.start();
113. break;
114. case 104:
115. //other thread通過Post Runnable方式發送消息給主線程
116. postRunnable = true;
117. noLooerThread = new NoLooperThread();
118. noLooerThread.start();
119. break;
120. case 105:
121. //主線程發送消息給other thread
122. if(null!=mOtherThreadHandler){
123. tv.setText("please look at the error level log for other thread received message from main thread");
124. String msgObj = "message from mainThread";
125. Message mainThreadMsg = mOtherThreadHandler.obtainMessage(1, 1, 1, msgObj);
126. mOtherThreadHandler.sendMessage(mainThreadMsg);
127. }
128. break;
129. case 106:
130. finish();
131. break;
132. }
133. }
134. class EventHandler extends Handler
135. {
136. public EventHandler(Looper looper) {
137. super(looper);
138. }
139. public EventHandler() {
140. super();
141. }
142. public void handleMessage(Message msg) {
143. //可以根據msg.what執行不同的處理,這裡沒有這麼做
144. switch(msg.what){
145. case 1:
146. tv.setText((String)msg.obj);
147. break;
148. case 2:
149. tv.setText((String)msg.obj);
150. noLooerThread.stop();
151. break;
152. case 3:
153. //不能在非主線程的線程裡面更新UI,所以這裡通過Log打印收到的消息
154. Log.e(sTag, (String)msg.obj);
155. ownLooperThread.stop();
156. break;
157. default:
158. //不能在非主線程的線程裡面更新UI,所以這裡通過Log打印收到的消息
159. Log.e(sTag, (String)msg.obj);
160. break;
161. }
162. }
163. }
164. //NoLooperThread
165. class NoLooperThread extends Thread{
166. private EventHandler mNoLooperThreadHandler;
167. public void run() {
168. Looper myLooper, mainLooper;
169. myLooper = Looper.myLooper();
170. mainLooper = Looper.getMainLooper(); //這是一個static函數
171. String obj;
172. if(myLooper == null){
173. mNoLooperThreadHandler = new EventHandler(mainLooper);
174. obj = "NoLooperThread has no looper and handleMessage function executed in main thread!";
175. }
176. else {
177. mNoLooperThreadHandler = new EventHandler(myLooper);
178. obj = "This is from NoLooperThread self and handleMessage function executed in NoLooperThread!";
179. }
180. mNoLooperThreadHandler.removeMessages(0);
181. if(false == postRunnable){
182. //send message to main thread
183. Message m = mNoLooperThreadHandler.obtainMessage(2, 1, 1, obj);
184. mNoLooperThreadHandler.sendMessage(m);
185. Log.e(sTag, "NoLooperThread id:" + this.getId());
186. }else{
187. //下面new出來的實現瞭Runnable接口的對象中run函數是在Main Thread中執行,不是在NoLooperThread中執行
188. //註意Runnable是一個接口,它裡面的run函數被執行時不會再新建一個線程
189. //您可以在run上加斷點然後在eclipse調試中看它在哪個線程中執行
190. mNoLooperThreadHandler.post(new Runnable(){
191. @Override
192. public void run() {
193. tv.setText("update UI through handler post runnalbe mechanism!");
194. noLooerThread.stop();
195. }
196. });
197. }
198. }
199. }
200.
201. //OwnLooperThread has his own message queue by execute Looper.prepare();
202. class OwnLooperThread extends Thread{
203. private EventHandler mOwnLooperThreadHandler;
204. public void run() {
205. Looper.prepare();
206. Looper myLooper, mainLooper;
207. myLooper = Looper.myLooper();
208. mainLooper = Looper.getMainLooper(); //這是一個static函數
209. String obj;
210. if(myLooper == null){
211. mOwnLooperThreadHandler = new EventHandler(mainLooper);
212. obj = "OwnLooperThread has no looper and handleMessage function executed in main thread!";
213. }
214. else {
215. mOwnLooperThreadHandler = new EventHandler(myLooper);
216. obj = "This is from OwnLooperThread self and handleMessage function executed in NoLooperThread!";
217. }
218. mOwnLooperThreadHandler.removeMessages(0);
219. //給自己發送消息
220. Message m = mOwnLooperThreadHandler.obtainMessage(3, 1, 1, obj);
221. mOwnLooperThreadHandler.sendMessage(m);
222. Looper.loop();
223. }
224. }
225.
226. //ReceiveMessageThread has his own message queue by execute Looper.prepare();
227. class ReceiveMessageThread extends Thread{
228. public void run() {
229. Looper.prepare();
230. mOtherThreadHandler = new Handler(){
231. public void handleMessage(Message msg) {
232. Log.e(sTag, (String)msg.obj);
233. }
234. };
235. Looper.loop();
236. }
237. }
238.
239. }
說明(代碼詳細解釋請見後文):
使用Looper.myLooper靜態方法可以取得當前線程的Looper對象。
使用mHandler = new EevntHandler(Looper.myLooper()); 可建立用來處理當前線程的Handler對象;其中,EevntHandler是Handler的子類。
使用mHandler = new EevntHandler(Looper.getMainLooper()); 可建立用來處理main線程的Handler對象;其中,EevntHandler是Handler的子類。
1.5.1.主線程給自己發送消息示例
主線程發送消息:
在onClick的case 101中創建一個繼承自Handler的EventHandler對象,然後獲取一個消息,然後通過EventHandler對象調用 sendMessage把消息發送到主線程的MessageQueue中。主線程由系統創建,系統會給它建立一個Looper對象和 MessageQueue,所以可以接收消息。這裡隻要根據主線程的Looper對象初始化EventHandler對象,就可以通過 EventHandler對象發送消息到主線程的消息隊列中。
主線程處理消息:
這裡是通過EventHandler的handleMessage函數處理的,其中收到的Message對象中what值為一的消息就是發送給它的,然後把消息裡面附帶的字符串在TextView上顯示出來。
1.5.2.其他線程給主線程發送消息示例
其他線程發送消息(這裡是說不使用Runnable作為callback的消息):
首先 postRunnable設為false,表示不通過Runnable方式進行消息相關的操作。然後啟動線程noLooerThread,然後以主線程的Looper對象為參數建立EventHandler的對象mNoLooperThreadHandler,然後獲取一個Message並把一個字符串賦值給它的一個成員obj,然後通過mNoLooperThreadHandler把消息發送到主線程的MessageQueue中。
主線程處理消息:
這裡是通過EventHandler的handleMessage函數處理的,其中收到的Message對象中what值為二的消息就是上面發送給它的,然後把消息裡面附帶的字符串在TextView上顯示出來。
1.5.3.其他線程給自己發送消息示例
其他線程發送消息:
其他非主線程建立後沒有自己的Looper對象,所以也沒有MessageQueue,需要給非主線程發送消息時需要建立MessageQueue以便接收消息。下面說明如何給自己建立MessageQueue和Looper對象。從OwnLooperThread的run函數中可以看見有一個 Looper.prepare()調用,這個就是用來建立非主線程的MessageQueue和Looper對象的。
所以這裡的發送消息過程是建立線程mOwnLooperThread,然後線程建立自己的Looper和MessageQueue對象,然後根據上面建立的Looper對象建立對應的EventHandler對象mOwnLooperThreadHandler,然後由mOwnLooperThreadHandler建立消息並且發送到自己的MessageQueue裡面。
其他線程處理接收的消息:
線程要接收消息需要在run函數中調用Looper.loop(),然後loop函數會從MessageQueue中取出消息交給對應的Handler對象 mOwnLooperThreadHandler處理,在mOwnLooperThreadHandler的handleMessage函數中會把 Message對象中what值為三的消息(上面發送的消息)在Log中打印出來,可以通過Logcat工具查看log。
1.5.4.其他線程以Runnable為消息參數給主線程發送消息示例
其他線程發送消息(這裡是說使用Runnable作為callback的消息):
首先 postRunnable設為true,表示通過Runnable方式進行消息相關的操作。然後啟動線程noLooerThread,然後以主線程的Looper對象為參數建立EventHandler的對象mNoLooperThreadHandler,然後獲取一個Message並把一個字符串賦值給它的一個成員obj,然後通過mNoLooperThreadHandler把消息發送到主線程的MessageQueue中。
主線程處理消息:
主線程收到上面發送的Message後直接運行上面Runnable對象中的run函數進行相應的操作。run函數通過Log打印一個字符串,可以通過Logcat工具查看log。
1.5.5.主線程給其他線程發送消息示例
主線程發送消息:
這裡首先要求線程receiveMessageThread運行(在onCreate函數中完成),並且準備好自己的Looper和 MessageQueue(這個通過ReceiveMessageThread中的run函數中的Looper.prepare()調用完成),然後根據建立的Looper對象初始化Handler對象mOtherThreadHandler。然後在onClick的case 105中由mOtherThreadHandler建立一個消息(消息中有一個字符串對象)並且發送到線程receiveMessageThread中的 MessageQueue中。
其他線程處理接收的消息:
線程要接收消息需要在run函數中調用Looper.loop(),然後loop函數會從MessageQueue中取出消息交給對應的Handler對象mOtherThreadHandler處理,在mOtherThreadHandler的handleMessage函數中會把Message對象中的字符串對象在Log中打印出來,可以通過Logcat工具查看log。