版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Handler Looper与MessageQueue源码分析在Android中可以通过Handler来更新主线程中UI的变化,更新UI只能在主线程中进行更新,而为了让其他线程也能控制UI的变化,Android提供了一种机制Handler、Looper与MessageQueue一同协作来达到其他线程更新UI的目的。作者:idisfkj来源:segmentfault|2016-10-21 13:03 收藏 分享 在Android中可以通过Handler来更新主线程中UI的变化,更新UI只能在主线程中进行更新,而为了让其他线程也能控制UI的变化,Android提供
2、了一种机制Handler、Looper与MessageQueue一同协作来达到其他线程更新UI的目的。一般我们会在主线程中通过如下方法定义一个Handler1. private Handler mHandler = new Handler() 2. Override 3. public void hand
3、leMessage(Message msg) 4. tv.setText("mHandler change UI"); 5. super.handleMessage(msg); 6.
4、 7. 一般都见不到Looper与MessageQueue的,那么它们都是在哪里调用与如何协作的呢?在主线程不会显式的调用Looper而是会在ActivityThread.main方法中默认调用。1. public static void main(String args) 2. Tra
5、ce.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); 3. SamplingProfilerIntegration.start(); 4. 5. / CloseGuard defaults to true&
6、#160;and can be quite spammy. We 6. / disable it here, but selectively enable it later (via 7. / StrictMode)
7、;on debug builds, but using DropBox, not logs. 8. CloseGuard.setEnabled(false); 9. 10. Environment.initForCurrentUser(); 11. 12. &
8、#160; / Set the reporter for event logging in libcore 13. EventLogger.setReporter(new EventLoggingReporter(); 14. 15.
9、160; / Make sure TrustedCertificateStore looks in the right place for CA certificates 16. final File configDir = Environment.getUserConfigDirectory(UserHan
10、dle.myUserId(); 17. TrustedCertificateStore.setDefaultUserDirectory(configDir); 18. 19. Process.setArgV0("<pre-initialized>"); 20. 21.
11、160; Looper.prepareMainLooper();/创建Looper 22. 23. ActivityThread thread = new ActivityThread(); 24. thread.attach(false);
12、25. 26. if (sMainThreadHandler = null) 27. sMainThreadHandler = thread.getHandler(); 28.
13、160; 29. 30. if (false) 31. Looper.myLooper().setMessageLogging(new 32.
14、0; LogPrinter(Log.DEBUG, "ActivityThread"); 33. 34. 35. / End of event ActivityThreadMain.
15、60;36. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 37. Looper.loop();/开启Looper循环 38. 39. throw new RuntimeExcept
16、ion("Main thread loop unexpectedly exited"); 40. 如上代码,调用了Looper.prepareMainLooper()方法,在主线程中创建了一个Looper,不信的话我们再查看该方法做了什么Looperprepare1. public static void prepare() 2.
17、 prepare(true); 3. 4. 5. private static void prepare(boolean quitAllowed) 6. if (sThreadLocal.get() != null) 7. &
18、#160; throw new RuntimeException("Only one Looper may be created per thread"); 8. 9.
19、 sThreadLocal.set(new Looper(quitAllowed);/创建Looper并赋给sThreadLocal 10. 11. 12. /* 13. * Initialize the current thread as a looper, marking
20、 it as an 14. * application's main looper. The main looper for your application 15. * is created by the Android environment, so
21、0;you should never need 16. * to call this function yourself. See also: link #prepare() 17. */ 18. public static void pr
22、epareMainLooper() 19. prepare(false); 20. synchronized (Looper.class) 21. if (sMainLooper
23、!= null) 22. throw new IllegalStateException("The main Looper has already been prepared."); 23. &
24、#160; 24. sMainLooper = myLooper(); 25. 26. 27. 28.
25、 public static Nullable Looper myLooper() 29. return sThreadLocal.get(); 30. 在prepareMainLooper方法中调用了prepare而通过prepare会发现它其实就是创建了一个Looper,并把它赋给了sThreadLocal。同
26、时可以通过myLooper方法获取当前线程中的Looper。再来看下new Looper(quitAllowed)初始化了什么1. private Looper(boolean quitAllowed) 2. mQueue = new MessageQueue(quitAllowed); 3. mThread =&
27、#160;Thread.currentThread(); 4. 在这里我们终于看到了MessageQueue了,它创建了一个MessageQueue。该消息队列就是用来保存后续的Message。再回到ActivityThread.main方法中,发现它调用了Looper.loop()是用来开启Looper循环的,监听消息队列MessageQueue中的消息。loop我们来看下Looper.loop()的源码:1. public static void loop()
28、0;2. final Looper me = myLooper();/获取Looper 3. if (me = null) 4. throw new
29、160;RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 5. 6. final MessageQueue queue = me.mQueu
30、e;/获取消息队列 7. 8. / Make sure the identity of this thread is that of the local process, 9. / and keep tr
31、ack of what that identity token actually is. 10. Binder.clearCallingIdentity(); 11. final long ident = Binder.clearCallingIdentity();
32、12. 13. for (;) 14. Message msg = queue.next(); / might block 15.
33、60; if (msg = null) 16. / No message indicates that the message queue is&
34、#160;quitting. 17. return; 18. 19. 20.
35、; / This must be in a local variable, in case a UI event sets the logger 21. final Printer logging = me.mLogging; 22.
36、 if (logging != null) 23. logging.println(">>>>> Dispatching to "
37、160;+ msg.target + " " + 24. msg.callback + ": " + msg.what); 25.
38、0; 26. 27. final long traceTag = me.mTraceTag; 28. if&
39、#160;(traceTag != 0) 29. Trace.traceBegin(traceTag, msg.target.getTraceName(msg); 30. 31.
40、; try 32. msg.target.dispatchMessage(msg);/通过Handler分发消息 33.
41、160; finally 34. if (traceTag != 0) 35.
42、160;Trace.traceEnd(traceTag); 36. 37. 38. 39.
43、60; if (logging != null) 40. logging.println("<<<<< Finished to " + msg.target + " " +&
44、#160;msg.callback); 41. 42. 43. / Make sure that during the course of dispatching the
45、60;44. / identity of the thread wasn't corrupted. 45. final long newIdent = Binder.clearCallingId
46、entity(); 46. if (ident != newIdent) 47. Log.wtf(TAG, "Thread identity changed
47、60;from 0x" 48. + Long.toHexString(ident) + " to 0x" 49.
48、160; + Long.toHexString(newIdent) + " while dispatching to " 50.
49、 + msg.target.getClass().getName() + " " 51. + msg.callback
50、0;+ " what=" + msg.what); 52. 53. 54. msg.recycleUnchecked(); 55.
51、160; 56. 在loop中首先获取了当前所在线程的Looper,同时也获取到了Looper中的MessageQueue,说明Looper已经与当前的线程进行了绑定。在后面开启了一个for的死循环,发现它做的事件是不断的从消息队列中取出消息,最后都交给msg.target调用它的dispatchMessage方法,那么target又是什么呢?我们进入MessageMessage1. /*package*/ int flags; 2. 3.
52、60; /*package*/ long when; 4. 5. /*package*/ Bundle data; 6. 7. /*package*/ Handler target; 8. 9.
53、160; /*package*/ Runnable callback; 10. 11. / sometimes we store linked lists of these things 12. /*package*/ Message next;
54、发现它就是我们熟悉的Handler,说明最后调用的就是Handler中的dispatchMessage方法,对消息的分发处理。这样一来Handler就通过Looper联系上了Looper所绑定的线程,即为主线程。Handler1. public Handler(Callback callback, boolean async) 2. if (FIND_POTENTIAL_LEAKS) 3.
55、160; final Class<? extends Handler> klass = getClass(); 4. if (klass.isAnonymousClass() | klass.isMemberClass()
56、160;| klass.isLocalClass() && 5. (klass.getModifiers() & Modifier.STATIC) = 0) 6.
57、0; Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 7.
58、 klass.getCanonicalName(); 8. 9. 10. 11. mLooper = L
59、ooper.myLooper(); 12. if (mLooper = null) 13. throw new RuntimeException( 14.
60、160; "Can't create handler inside thread that has not called Looper.prepare()"); 15. 16. mQueue
61、0;= mLooper.mQueue; 17. mCallback = callback; 18. mAsynchronous = async; 19. 通过Handler的初始化,它获取了它所处线程的Looper,同时也获取了Looper中的消息队列。当
62、然如果所处线程的Looper为空的话就会抛出异常,这就解释了为什么在非主线程中创建Handler要分别调用Looper.prepare与Looper.loop而主线程则不需要,因为它默认已经调用了。dispatchMessage1. public void dispatchMessage(Message msg) 2. if (msg.callback != null) 3.
63、0; handleCallback(msg); 4. else 5. if (mCallback != null) 6.
64、 if (mCallback.handleMessage(msg) 7. return; 8.
65、0; 9. 10. handleMessage(msg); 11.
66、0; 12. 13. private static void handleCallback(Message message) 14. message.callback.run(); 15. 回到前面,对于dispatchMessage的处理,
67、首先判断msg.callback是否为空,这里callback通过上面的Message应该能知道他就是一个Runnable,如果不为空则直接调用Runnable的run方法。否则调用Handler的handleMessage方法.而这个方法相信大家已经很熟悉了,对事件的处理都是在这个方法中执行的。因为通过前面我们已经知道了Handler已经联系上了主线程,所以handleMessage中的处理自然相对于在主线程中进行,自然也能更新UI了。通过这里我们能把Looper比作是一个桥梁,来连接Looper所在的线程与Handler之间的通信,同时管理消息队列MessageQueue中的消息。那么前面
68、的Runnable又是如何不为空的呢?我们使用Handler有两种方法,一种是直接创建一个Handler并且重写它的handleMessage方法,而另一种可以通过Handler.post(Runnable)来使用,这样事件的处理自然就在run方法中实现。上面介绍了Handler是如何联系上了需要操作的线程与对消息是如何取出与处理的。下面来谈谈消息是如何放入到Looper中的MessageQueue中的。sendMessageAtTime通过Handler发送消息的方式很多,例如:sendMessage、sendEmptyMessage与sendMessageDelayed等,其实到最后他们调
69、用的都是sendMessageAtTime方法。所以还是来看下sendMessageAtTime方法中的实现。1. public boolean sendMessageAtTime(Message msg, long uptimeMillis) 2. MessageQueue queue = mQueue; 3. if (queue = null) 4. &
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年矿产资源开发与合作合同
- 兼职文案创意撰写合同
- 交通运输工具融资租赁合同
- 环保工程桩基机械施工合同
- 智能电网通信网络升级合同
- 员工餐费补贴发放细则
- 餐厅浮雕施工协议
- 环保设施电工维护聘用协议
- 临时搭建物拆除合同
- 学校出租车租赁合同协议书
- 基于单片机数字秒表的设计
- 基于LabVIEW的温湿度监测系统
- 人保《理赔工作聘请保险公估机构管理办法》实施细则
- GB/T 40636-2021挂面
- GB/T 11348.3-1999旋转机械转轴径向振动的测量和评定第3部分:耦合的工业机器
- GB 18383-2007絮用纤维制品通用技术要求
- 台积电半导体制造自动化课件
- 法律专题(本)(52876)-国家开放大学电大学习网形考作业题目答案
- MVR热泵精馏处理回收稀DMAC水溶液
- 抢救车管理质控分析
- 采油站工艺流程图课件
评论
0/150
提交评论