加入收藏 | 设为首页 | 会员中心 | 我要投稿 东莞站长网 (https://www.0769zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长资讯 > 评论 > 正文

Android消息机制Handler,有必要再讲一次

发布时间:2019-07-28 07:42:38 所属栏目:评论 来源:Engineers
导读:副标题#e# 我们在日常开发中,总是不可避免的会用到 Handler,虽说 Handler 机制并不等同于 Android 的消息机制,但 Handler 的消息机制在 Android 开发中早已谙熟于心,非常重要! 通过本文,你可以非常容易得到一下问题的答案: Handler、Looper、Message

next() 方法其实很长,不过我们仅仅贴了极少的一部分,可以看到,里面不过是有一个 for (;;) 的无限循环,循环体内部调用了一个 nativePollOnce(long, int) 方法。这是一个 Native 方法,实际作用是通过 Native 层的 MessageQueue 阻塞当前调用栈线程 nextPollTimeoutMillis 毫秒的时间。

下面是 nextPollTimeoutMillis 取值的不同情况的阻塞表现:

  • 小于 0,一直阻塞,直到被唤醒;
  • 等于 0,不会阻塞;
  • 大于 0,最长阻塞 nextPollTimeoutMillis 毫秒,期间如被唤醒会立即返回。

可以看到,最开始 nextPollTimeoutMillis 的初始化值是 0,所以不会阻塞,会直接去取 Message 对象,如果没有取到 Message 对象数据,则直接会把 nextPollTimeoutMillis 置为 -1,此时满足小于 0 的条件,会被一直阻塞,直到其他地方调用另外一个 Native 方法 nativeWake(long) 进行唤醒。如果取到值的话,会直接把得到的 Message 对象进行返回。

原来,nativeWake(long) 方法在前面的 MessageQueue#enqueueMessage 方法有个调用,调用时机是在 MessageQueue 入队消息的过程中。

现在已经知道:Handler 发送了 Message,消息用 MessageQueue 进行存储,使用 MessageQueue#enqueueMessage 方法进行入队,使用 MessageQueue#next 方法进行轮训消息。这就不免抛出了一个问题,MessageQueue#next 方法是谁调用的?没错,就是 Looper。

Looper

Looper 在 Android 的消息机制中扮演着消息循环的角色,具体来说就是它会不停地从 MessageQueue 通过 next() 查看是否有新消息,如果有新消息就立刻处理,否则就任由 MessageQueue 阻塞在那里。

我们直接看看 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.  // ... 
  7.  for (;;) { 
  8.  Message msg = queue.next(); // might block 
  9.  if (msg == null) { 
  10.  // No message indicates that the message queue is quitting. 
  11.  return; 
  12.  } 
  13.  //... 
  14.  try { 
  15.  // 分发消息给 handler 处理 
  16.  msg.target.dispatchMessage(msg); 
  17.  dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; 
  18.  } finally { 
  19.  // ... 
  20.  } 
  21.  // ... 
  22.  } 

方法省去了大量的代码,只保留了核心逻辑。可以看到,首先会通过 myLooper() 方法得到 Looper 对象,如果这个 Looper 返回为空的话,则直接抛出异常。否则进入到一个 for (;;) 循环中,调用 MessageQueue#next() 方法进行轮训获取 Message 对象,如果获取的 Message 对象为空,则直接退出 loop() 方法。否则直接通过 msg.target 拿到 Handler 对象,并调用 Handler#dispatchMessage() 方法。

我们先来看看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. private static void handleCallback(Message message) { 
  13.  message.callback.run(); 

代码比较简单,如果 Message 设置了 callback 则,直接调用 message.callback.run(),否则判断是否初始化了 `m

(编辑:东莞站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读