引用php
來自easyandroid論壇,原文:http://www.easyandroid.com/bbs/viewthread.php?tid=33java
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對象會和一個線程關聯
android
1. public static final void prepare() { app
2. if (sThreadLocal.get() != null) { eclipse
3. throw new RuntimeException("Only one Looper may be created per thread"); ide
4. } 函數
5. sThreadLocal.set(new Looper()); 工具
6. } oop
Looper對象建立時會建立一個MessageQueue,主線程默認會建立一個Looper從而有MessageQueue,其餘線程默認是沒有 MessageQueue的不能接收Message,若是須要接收Message則須要經過prepare函數建立一個MessageQueue。具體操做請見示例代碼。
1. private Looper() {
2. mQueue = new MessageQueue();
3. mRun = true;
4. mThread = Thread.currentThread();
5. }
prepareMainLooper函數只給主線程調用(系統處理,程序員不用處理),它會調用prepare創建Looper對象和MessageQueue。
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取出來作處理,經過這種方式作到消息的定時處理。
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接口的對象,後面會看到這個對象的做用。
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對象。
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的接收消息隊列中
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函數處理消息)。
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實例來展現對應的功能,程序界面於下:
程序代碼以下,後面部分有代碼說明:
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。