1.活用Android线程间通信的Message机制

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. publicstaticfinalvoidprepare(){
  2. if(sThreadLocal.get()!=null){
  3. thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");
  4. }
  5. sThreadLocal.set(newLooper());
  6. }


Looper对象创建时会创建一个MessageQueue,主线程默认会创建一个Looper从而有MessageQueue,其他线程默认是没有 MessageQueue的不能接收Message,如果需要接收Message则需要通过prepare函数创建一个MessageQueue。具体操作请见示例代码。

Java代码 收藏代码
  1. privateLooper(){
  2. mQueue=newMessageQueue();
  3. mRun=true;
  4. mThread=Thread.currentThread();
  5. }


prepareMainLooper函数只给主线程调用(系统处理,程序员不用处理),它会调用prepare建立Looper对象和MessageQueue。

Java代码 收藏代码
  1. publicstaticfinalvoidprepareMainLooper(){
  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. publicstaticfinalvoidloop(){
  2. Looperme=myLooper();
  3. MessageQueuequeue=me.mQueue;
  4. while(true){
  5. Messagemsg=queue.next();//mightblock
  6. //if(!me.mRun){
  7. //break;
  8. //}
  9. if(msg!=null){
  10. if(msg.target==null){
  11. //Notargetisamagicidentifierforthequitmessage
  12. return;
  13. }
  14. if(me.mLogging!=null)
  15. me.mLogging.println(">>>>>Dispatchingto"+msg.target+""+msg.callback+":"+msg.what);
  16. msg.target.dispatchMessage(msg);
  17. if(me.mLogging!=null)
  18. me.mLogging.println("<<<<<Finishedto"+msg.target+""+msg.callback);
  19. msg.recycle();
  20. }
  21. }
  22. }


1.4.Handler

Handler的构造函数表示Handler会有成员变量指向Looper和MessageQueue,后面我们会看到没什么需要这些引用;至于callback是实现了Callback接口的对象,后面会看到这个对象的作用。

Java代码 收藏代码
  1. publicHandler(Looperlooper,Callbackcallback){
  2. mLooper=looper;
  3. mQueue=looper.mQueue;
  4. mCallback=callback;
  5. }
  6. publicinterfaceCallback{
  7. publicbooleanhandleMessage(Messagemsg);
  8. }


获取消息:直接通过Message的obtain方法获取一个Message对象。

Java代码 收藏代码
  1. publicfinalMessageobtainMessage(intwhat,intarg1,intarg2,Objectobj){
  2. returnMessage.obtain(this,what,arg1,arg2,obj);
  3. }


发送消息:通过MessageQueue的enqueueMessage把Message对象放到MessageQueue的接收消息队列中

Java代码 收藏代码
  1. publicbooleansendMessageAtTime(Messagemsg,longuptimeMillis){
  2. booleansent=false;
  3. MessageQueuequeue=mQueue;
  4. if(queue!=null){
  5. msg.target=this;
  6. sent=queue.enqueueMessage(msg,uptimeMillis);
  7. }else{
  8. RuntimeExceptione=newRuntimeException(this+"sendMessageAtTime()calledwithnomQueue");
  9. Log.w("Looper",e.getMessage(),e);
  10. }
  11. returnsent;
  12. }



线程如何处理MessageQueue中接收的消息:在Looper的loop函数中循环取出MessageQueue的接收消息队列中的消息,然后调用 Hander的dispatchMessage函数对消息进行处理,至于如何处理(相应消息)则由用户指定(三个方法,优先级从高到低:Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工作;Handler里面的mCallback指向的一个实现了 Callback接口的对象,里面的handleMessage进行处理;处理消息Handler对象对应的类继承并实现了其中 handleMessage函数,通过这个实现的handleMessage函数处理消息)。

Java代码 收藏代码
  1. publicvoiddispatchMessage(Messagemsg){
  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,很多人有误解,所以这里澄清一下。


从上可知以下关系图:
Android中Message机制的灵活应用_第1张图片
其中清理Message是Looper里面的loop函数指把处理过的Message放到Message的Pool里面去,如果里面已经超过最大值10个,则丢弃这个Message对象。

调用Handler是指Looper里面的loop函数从MessageQueue的接收消息队列里面取出消息,然后根据消息指向的Handler对象调用其对应的处理方法。
1.5.代码示例

下面我们会以android实例来展示对应的功能,程序界面于下:
Android中Message机制的灵活应用_第2张图片
程序代码如下,后面部分有代码说明:

Java代码 收藏代码
  1. packagecom.android.messageexample;
  2. importandroid.app.Activity;
  3. importandroid.content.Context;
  4. importandroid.graphics.Color;
  5. importandroid.os.Bundle;
  6. importandroid.os.Handler;
  7. importandroid.os.Looper;
  8. importandroid.os.Message;
  9. importandroid.util.Log;
  10. importandroid.view.View;
  11. importandroid.view.View.OnClickListener;
  12. importandroid.widget.Button;
  13. importandroid.widget.LinearLayout;
  14. importandroid.widget.TextView;
  15. publicclassMessageExampleextendsActivityimplementsOnClickListener{
  16. privatefinalintWC=LinearLayout.LayoutParams.WRAP_CONTENT;
  17. privatefinalintFP=LinearLayout.LayoutParams.FILL_PARENT;
  18. publicTextViewtv;
  19. privateEventHandlermHandler;
  20. privateHandlermOtherThreadHandler=null;
  21. privateButtonbtn,btn2,btn3,btn4,btn5,btn6;
  22. privateNoLooperThreadnoLooerThread=null;
  23. privateOwnLooperThreadownLooperThread=null;
  24. privateReceiveMessageThreadreceiveMessageThread=null;
  25. privateContextcontext=null;
  26. privatefinalStringsTag="MessageExample";
  27. privatebooleanpostRunnable=false;
  28. /**Calledwhentheactivityisfirstcreated.*/
  29. @Override
  30. publicvoidonCreate(BundlesavedInstanceState){
  31. super.onCreate(savedInstanceState);
  32. context=this.getApplicationContext();
  33. LinearLayoutlayout=newLinearLayout(this);
  34. layout.setOrientation(LinearLayout.VERTICAL);
  35. btn=newButton(this);
  36. btn.setId(101);
  37. btn.setText("messagefrommainthreadself");
  38. btn.setOnClickListener(this);
  39. LinearLayout.LayoutParamsparam=
  40. newLinearLayout.LayoutParams(250,50);
  41. param.topMargin=10;
  42. layout.addView(btn,param);
  43. btn2=newButton(this);
  44. btn2.setId(102);
  45. btn2.setText("messagefromotherthreadtomainthread");
  46. btn2.setOnClickListener(this);
  47. layout.addView(btn2,param);
  48. btn3=newButton(this);
  49. btn3.setId(103);
  50. btn3.setText("messagetootherthreadfromitself");
  51. btn3.setOnClickListener(this);
  52. layout.addView(btn3,param);
  53. btn4=newButton(this);
  54. btn4.setId(104);
  55. btn4.setText("messagewithRunnableascallbackfromotherthreadtomainthread");
  56. btn4.setOnClickListener(this);
  57. layout.addView(btn4,param);
  58. btn5=newButton(this);
  59. btn5.setId(105);
  60. btn5.setText("mainthread'smessagetootherthread");
  61. btn5.setOnClickListener(this);
  62. layout.addView(btn5,param);
  63. btn6=newButton(this);
  64. btn6.setId(106);
  65. btn6.setText("exit");
  66. btn6.setOnClickListener(this);
  67. layout.addView(btn6,param);
  68. tv=newTextView(this);
  69. tv.setTextColor(Color.WHITE);
  70. tv.setText("");
  71. LinearLayout.LayoutParamsparam2=
  72. newLinearLayout.LayoutParams(FP,WC);
  73. param2.topMargin=10;
  74. layout.addView(tv,param2);
  75. setContentView(layout);
  76. //主线程要发送消息给otherthread,这里创建那个otherthread
  77. receiveMessageThread=newReceiveMessageThread();
  78. receiveMessageThread.start();
  79. }
  80. //implementtheOnClickListenerinterface
  81. @Override
  82. publicvoidonClick(Viewv){
  83. switch(v.getId()){
  84. case101:
  85. //主线程发送消息给自己
  86. Looperlooper;
  87. looper=Looper.myLooper();//gettheMainlooperrelatedwiththemainthread
  88. //如果不给任何参数的话会用当前线程对应的Looper(这里就是MainLooper)为Handler里面的成员mLooper赋值
  89. mHandler=newEventHandler(looper);
  90. //mHandler=newEventHandler();
  91. //清除整个MessageQueue里的消息
  92. mHandler.removeMessages(0);
  93. Stringobj="Thismainthread'smessageandreceivedbyitself!";
  94. //得到Message对象
  95. Messagem=mHandler.obtainMessage(1,1,1,obj);
  96. //将Message对象送入到mainthread的MessageQueue里面
  97. mHandler.sendMessage(m);
  98. break;
  99. case102:
  100. //other线程发送消息给主线程
  101. postRunnable=false;
  102. noLooerThread=newNoLooperThread();
  103. noLooerThread.start();
  104. break;
  105. case103:
  106. //otherthread获取它自己发送的消息
  107. tv.setText("pleaselookattheerrorlevellogforotherthreadreceivedmessage");
  108. ownLooperThread=newOwnLooperThread();
  109. ownLooperThread.start();
  110. break;
  111. case104:
  112. //otherthread通过PostRunnable方式发送消息给主线程
  113. postRunnable=true;
  114. noLooerThread=newNoLooperThread();
  115. noLooerThread.start();
  116. break;
  117. case105:
  118. //主线程发送消息给otherthread
  119. if(null!=mOtherThreadHandler){
  120. tv.setText("pleaselookattheerrorlevellogforotherthreadreceivedmessagefrommainthread");
  121. StringmsgObj="messagefrommainThread";
  122. MessagemainThreadMsg=mOtherThreadHandler.obtainMessage(1,1,1,msgObj);
  123. mOtherThreadHandler.sendMessage(mainThreadMsg);
  124. }
  125. break;
  126. case106:
  127. finish();
  128. break;
  129. }
  130. }
  131. classEventHandlerextendsHandler
  132. {
  133. publicEventHandler(Looperlooper){
  134. super(looper);
  135. }
  136. publicEventHandler(){
  137. super();
  138. }
  139. publicvoidhandleMessage(Messagemsg){
  140. //可以根据msg.what执行不同的处理,这里没有这么做
  141. switch(msg.what){
  142. case1:
  143. tv.setText((String)msg.obj);
  144. break;
  145. case2:
  146. tv.setText((String)msg.obj);
  147. noLooerThread.stop();
  148. break;
  149. case3:
  150. //不能在非主线程的线程里面更新UI,所以这里通过Log打印收到的消息
  151. Log.e(sTag,(String)msg.obj);
  152. ownLooperThread.stop();
  153. break;
  154. default:
  155. //不能在非主线程的线程里面更新UI,所以这里通过Log打印收到的消息
  156. Log.e(sTag,(String)msg.obj);
  157. break;
  158. }
  159. }
  160. }
  161. //NoLooperThread
  162. classNoLooperThreadextendsThread{
  163. privateEventHandlermNoLooperThreadHandler;
  164. publicvoidrun(){
  165. LoopermyLooper,mainLooper;
  166. myLooper=Looper.myLooper();
  167. mainLooper=Looper.getMainLooper();//这是一个static函数
  168. Stringobj;
  169. if(myLooper==null){
  170. mNoLooperThreadHandler=newEventHandler(mainLooper);
  171. obj="NoLooperThreadhasnolooperandhandleMessagefunctionexecutedinmainthread!";
  172. }
  173. else{
  174. mNoLooperThreadHandler=newEventHandler(myLooper);
  175. obj="ThisisfromNoLooperThreadselfandhandleMessagefunctionexecutedinNoLooperThread!";
  176. }
  177. mNoLooperThreadHandler.removeMessages(0);
  178. if(false==postRunnable){
  179. //sendmessagetomainthread
  180. Messagem=mNoLooperThreadHandler.obtainMessage(2,1,1,obj);
  181. mNoLooperThreadHandler.sendMessage(m);
  182. Log.e(sTag,"NoLooperThreadid:"+this.getId());
  183. }else{
  184. //下面new出来的实现了Runnable接口的对象中run函数是在MainThread中执行,不是在NoLooperThread中执行
  185. //注意Runnable是一个接口,它里面的run函数被执行时不会再新建一个线程
  186. //您可以在run上加断点然后在eclipse调试中看它在哪个线程中执行
  187. mNoLooperThreadHandler.post(newRunnable(){
  188. @Override
  189. publicvoidrun(){
  190. tv.setText("updateUIthroughhandlerpostrunnalbemechanism!");
  191. noLooerThread.stop();
  192. }
  193. });
  194. }
  195. }
  196. }
  197. //OwnLooperThreadhashisownmessagequeuebyexecuteLooper.prepare();
  198. classOwnLooperThreadextendsThread{
  199. privateEventHandlermOwnLooperThreadHandler;
  200. publicvoidrun(){
  201. Looper.prepare();
  202. LoopermyLooper,mainLooper;
  203. myLooper=Looper.myLooper();
  204. mainLooper=Looper.getMainLooper();//这是一个static函数
  205. Stringobj;
  206. if(myLooper==null){
  207. mOwnLooperThreadHandler=newEventHandler(mainLooper);
  208. obj="OwnLooperThreadhasnolooperandhandleMessagefunctionexecutedinmainthread!";
  209. }
  210. else{
  211. mOwnLooperThreadHandler=newEventHandler(myLooper);
  212. obj="ThisisfromOwnLooperThreadselfandhandleMessagefunctionexecutedinNoLooperThread!";
  213. }
  214. mOwnLooperThreadHandler.removeMessages(0);
  215. //给自己发送消息
  216. Messagem=mOwnLooperThreadHandler.obtainMessage(3,1,1,obj);
  217. mOwnLooperThreadHandler.sendMessage(m);
  218. Looper.loop();
  219. }
  220. }
  221. //ReceiveMessageThreadhashisownmessagequeuebyexecuteLooper.prepare();
  222. classReceiveMessageThreadextendsThread{
  223. publicvoidrun(){
  224. Looper.prepare();
  225. mOtherThreadHandler=newHandler(){
  226. publicvoidhandleMessage(Messagemsg){
  227. Log.e(sTag,(String)msg.obj);
  228. }
  229. };
  230. Looper.loop();
  231. }
  232. }
  233. }

说明(代码详细解释请见后文):

使用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。

更多相关文章

  1. C语言函数以及函数的使用
  2. Android 源码分析 - 消息处理机制
  3. Android中的Parcel机制 实现Bundle传递对象
  4. Android核心分析 之十一-------Android GWES之消息系统
  5. Android消息推送MQTT
  6. android NDK JNI设置自己的log输出函数

随机推荐

  1. Android studio 插件安装
  2. Android设置透明、半透明等效果
  3. Android中Toast如何在子线程中调用
  4. android avd配置路径
  5. Mac配置Android环境变量
  6. 百度地图JS使用
  7. android TextView的字体颜色设置的多种方
  8. Android参数传递总结
  9. Google Android(安卓)JNI使用方法
  10. App自动更新之自定义进度视图和内部存储