资讯专栏INFORMATION COLUMN

Handler详解

Caizhenhao / 1414人阅读

我们在new Handler()时候,实际上调用的是两个参数的构造方法,我们看下

</>复制代码

  1. public Handler() {
  2. this(null, false);
  3. }

</>复制代码

  1. public Handler(Callback callback, boolean async) {
  2. if (FIND_POTENTIAL_LEAKS) {
  3. final Class klass = getClass();
  4. if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
  5. (klass.getModifiers() & Modifier.STATIC) == 0) {
  6. Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
  7. klass.getCanonicalName());
  8. }
  9. }
  10. mLooper = Looper.myLooper();
  11. if (mLooper == null) {
  12. throw new RuntimeException(
  13. "Can"t create handler inside thread that has not called Looper.prepare()");
  14. }
  15. mQueue = mLooper.mQueue;
  16. // mCallback null
  17. mCallback = callback;
  18. // mAsynchronous false
  19. mAsynchronous = async;
  20. }

我们看下myLooper()方法,

</>复制代码

  1. public static @Nullable Looper myLooper() {
  2. return sThreadLocal.get();
  3. }

sThreadLocal是什么我们看下:

</>复制代码

  1. // sThreadLocal.get() will return null unless you"ve called prepare().
  2. static final ThreadLocal sThreadLocal = new ThreadLocal();

在没有调用Looper的prepare()情况下回返回null,我们看下prepare()方法的实现:

</>复制代码

  1. private static void prepare(boolean quitAllowed) {
  2. //一个Thread只能有一个Looper绑定
  3. if (sThreadLocal.get() != null) {
  4. throw new RuntimeException("Only one Looper may be created per thread");
  5. }
  6. sThreadLocal.set(new Looper(quitAllowed));
  7. }

现在终于可以看下Looper是构造方法了

</>复制代码

  1. private Looper(boolean quitAllowed) {
  2. mQueue = new MessageQueue(quitAllowed);
  3. mThread = Thread.currentThread();
  4. }

到这里Handler的mLooper和mQueue就找到出处了

我们看下sendMessage()做了什么:

</>复制代码

  1. public final boolean sendMessage(Message msg)
  2. {
  3. return sendMessageDelayed(msg, 0);
  4. }

</>复制代码

  1. public final boolean sendMessageDelayed(Message msg, long delayMillis)
  2. {
  3. if (delayMillis < 0) {
  4. delayMillis = 0;
  5. }
  6. //uptimeMillis() 从开机到现在的毫秒数
  7. return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
  8. }

</>复制代码

  1. public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
  2. //looper中创建的queue
  3. MessageQueue queue = mQueue;
  4. if (queue == null) {
  5. RuntimeException e = new RuntimeException(
  6. this + " sendMessageAtTime() called with no mQueue");
  7. Log.w("Looper", e.getMessage(), e);
  8. return false;
  9. }
  10. // 加入队列
  11. return enqueueMessage(queue, msg, uptimeMillis);
  12. }

</>复制代码

  1. private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
  2. // 在这里我们注意下我们给msg添加了一个target是handler对象
  3. msg.target = this;
  4. if (mAsynchronous) {
  5. msg.setAsynchronous(true);
  6. }
  7. return queue.enqueueMessage(msg, uptimeMillis);
  8. }

这里调用了MessageQueue的enqueueMessae()方法,把我们的msg添加到queue里

我们再来看下Looper.loop()方法:

</>复制代码

  1. public static void loop() {
  2. final Looper me = myLooper();
  3. if (me == null) {
  4. throw new RuntimeException("No Looper; Looper.prepare() wasn"t called on this thread.");
  5. }
  6. final MessageQueue queue = me.mQueue;
  7. // Make sure the identity of this thread is that of the local process,
  8. // and keep track of what that identity token actually is.
  9. Binder.clearCallingIdentity();
  10. final long ident = Binder.clearCallingIdentity();
  11. for (;;) {
  12. Message msg = queue.next(); // might block
  13. if (msg == null) {
  14. // No message indicates that the message queue is quitting.
  15. return;
  16. }
  17. // This must be in a local variable, in case a UI event sets the logger
  18. final Printer logging = me.mLogging;
  19. if (logging != null) {
  20. logging.println(">>>>> Dispatching to " + msg.target + " " +
  21. msg.callback + ": " + msg.what);
  22. }
  23. final long traceTag = me.mTraceTag;
  24. if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
  25. Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
  26. }
  27. try {
  28. //==================================================================
  29. // 重点代码在这里
  30. msg.target.dispatchMessage(msg);
  31. //==================================================================
  32. } finally {
  33. if (traceTag != 0) {
  34. Trace.traceEnd(traceTag);
  35. }
  36. }
  37. if (logging != null) {
  38. logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
  39. }
  40. // Make sure that during the course of dispatching the
  41. // identity of the thread wasn"t corrupted.
  42. final long newIdent = Binder.clearCallingIdentity();
  43. if (ident != newIdent) {
  44. Log.wtf(TAG, "Thread identity changed from 0x"
  45. + Long.toHexString(ident) + " to 0x"
  46. + Long.toHexString(newIdent) + " while dispatching to "
  47. + msg.target.getClass().getName() + " "
  48. + msg.callback + " what=" + msg.what);
  49. }
  50. msg.recycleUnchecked();
  51. }
  52. }

重点代码是 msg.target.dispatchMessage(msg);这句代码,msg的target对象实际就是Handler,我们看下Handler的dispatchMessage()方法。

</>复制代码

  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. }

看到了我们熟悉的handleMessaee()方法

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70227.html

相关文章

  • Handler 使用详解

    摘要:机制处理的个关键对象线程之间传递的消息,可以携带一些简单的数据供子线程与主线程进行交换数据。解决方法子线程通过发送消息给主线程,让主线程处理消息,进而更新。 showImg(https://segmentfault.com/img/remote/1460000019975019?w=157&h=54); 极力推荐文章:欢迎收藏Android 干货分享 showImg(https://...

    sihai 评论0 收藏0
  • js事件详解

    摘要:事件流事件流描述的是从页面中接收事件的顺序。其次,必须事先指定所有事件处理程序而导致的访问次数,会延迟整个页面的交互就绪时间。 1.事件流 事件流描述的是从页面中接收事件的顺序。 1.1 事件冒泡 IE中的事件流叫做冒泡,即时间最开始由最具体的元素接收,然后逐级向上传播到较为不具体的节点,直到传播到document对象。例: Event Exampple ...

    BDEEFE 评论0 收藏0
  • js事件详解二:鼠标和滚轮事件

    摘要:在级事件中定义了个鼠标事件,分别是。取消鼠标事件的默认行为还会影响其他事件,因为鼠标事件与其他事件是密不可分的关系。同样的,和支持这个事件。兼容各个浏览器的事件监听对象该对象封装了和级事件的常用事件函数。 概述 鼠标事件是web开发中最常用的一类事件,毕竟鼠标还是最主要的定位设备。在DOM3级事件中定义了9个鼠标事件,分别是:click,dbclick,mousedown,mousee...

    Lucky_Boy 评论0 收藏0
  • js事件详解

    摘要:使用级方法指定的事件处理程序被认为是元素的方法。用于立即停止事件在中的传播,取消进一步的事件捕获或冒泡。捕获事件目标对象冒泡只有在事件处理程序执行期间,对象才会存在,执行完成后,对象就会被销毁。 引用 事件是我认为前端最特别的地方,这是唯一其他语言不一样的地方,我们通过它与页面进行交互。 事件流 事件流描述的是从页面中接收事件的顺序。IE和网景团队提出流相反的事件流概念。IE事件流是事...

    AlienZHOU 评论0 收藏0

发表评论

0条评论

Caizhenhao

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<