为了账号安全,请及时绑定邮箱和手机立即绑定

Android 9.0 源码_机制篇 -- 全面解析 Handler 机制(原理篇)下

标签:
Android

开篇


上一篇说到曹操败走华容道后...咳咳,不好意思走错片场了。需要看上篇的同学出门左拐点主页观看

8.quit()

 public void quit() {
        mQueue.quit(false);          // 消息移除
    }    public void quitSafely() {
        mQueue.quit(true);           // 安全消息移除
    }

Looper.quit() 方法的实现最终调用的是 MessageQueue.quit() 方法。

9.MessageQueue.quit()

void quit(boolean safe) {        if (!mQuitAllowed) {    当 mQuitAllowed 为 false,表示不运行退出,强行调用 quit() 会抛出异常
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {            if (mQuitting) {                return;
            }
            mQuitting = true;            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }

消息退出的方式:######1.当 safe = true 时,只移除尚未触发的所有消息,对于正在触发的消息并不移除######2.当 safe = flase 时,移除所有的消息#三Handler-------------------------------------------------------------##构造函数-------------------------------------------------------------### 无参构造
public Handler() {    this(null, false);
}public Handler(Callback callback) {    this(callback, false);
}public Handler(boolean async) {    this(null, async);
}public Handler(Callback callback, boolean async) {    // 匿名类、内部类或本地类都必须申明为static,否则会警告可能出现内存泄露
    if (FIND_POTENTIAL_LEAKS) {     // 默认为 false
        final Class<? extends Handler> klass = getClass();        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }
对于 Handler 的无参构造方法,默认采用当前线程 TLS 中的 Looper 对象,并且 callback 回调方法为 null,且消息为同步处理方式。只要执行的 Looper.prepare() 方法,那么便可以获取有效的 Looper 对象。

1.dispatchMessage()


在 Looper.loop() 中,当发现有消息时,调用消息的目标 handler,执行 dispatchMessage() 方法来分发消息。

   /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {        if (msg.callback != null) {            // 当 Message 存在回调方法,回调 msg.callback.run() 方法
            handleCallback(msg);
        } else {            if (mCallback != null) {                // 当 Handler 存在 Callback 成员变量时,回调方法 handleMessage()
                if (mCallback.handleMessage(msg)) {                    return;
                }
            }            // Handler 自身的回调方法 handleMessage()
            handleMessage(msg);
        }
    }

我们需要重点分析下这个函数:

首先会判断 msg.callback 存不存在,msg.callback 是 Runnable 类型,如果 msg.callback 存在,那么说明该 Message 是通过执行 Handler 的 post() 系列方法将 Message 放入到消息队列中的,这种情况下会执行 handleCallback(msg)。

2.handleCallback

源码如下:

    private static void handleCallback(Message message) {
        message.callback.run();
    }

这样我们就清楚地看到我们执行了 msg.callback 的 run 方法,也就是执行了 post() 所传递的 Runnable 对象的 run 方法。

3.mCallback

如果我们不是通过 post() 系列方法将 Message 放入到消息队列中的,那么 msg.callback 就是 null ,代码继续往下执行。

接着我们会判断 Handler 的成员字段 mCallback 存不存在。mCallback 是 Hanlder.Callback 类型的,我们在上面提到过,在 Handler 的构造函数中我们可以传递 Hanlder.Callback 类型的对象,该对象需要实现 handleMessage 方法,如果我们在构造函数中传递了该 Callback 对象,那么我们就会让 Callback 的 handleMessage 方法来处理 Message。

    final Callback mCallback;    
    public interface Callback {        /**
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         */
        public boolean handleMessage(Message msg);
    }
如果我们在构造函数中没有传入 Callback 类型的对象,那么 mCallback 就为 null ,那么我们会调用 Handler 自身的 hanldeMessage 方法,该方法默认是个空方法,我们需要自己重写实现该方法。
    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {      // 空函数
    }

综上所述,我们可以看到 Handler 提供了三种途径处理 Message ,而且处理有前后优先级之分:首先尝试让 post() 中传递的 Runnable 执行,其次尝试让 Handler 构造函数中传入的 Callback 的 handleMessage 方法处理,最后才是让 Handler 自身的 handleMessage 方法处理Message。

4.Callback

Callback 是 Handle r中的内部接口,需要实现其内部的 handleMessage 方法,Callback 代码如下:

    public interface Callback {        public boolean handleMessage(Message msg);
    }

Handler.Callback 是用来处理 Message 的一种手段,如果没有传递该参数,那么就应该重写 Handler 的 handleMessage 方法,也就是说为了使得 Handler 能够处理 Message ,有两种办法:

1.向 Hanlder 的构造函数传入一个 Handler.Callback 对象,并实现 Handler.Callback 的 handleMessage 方法
2.无需向 Hanlder 的构造函数传入 Handler.Callback 对象,但是需要重写 Handler 本身的 handleMessage 方法

也就是说无论哪种方式,我们都得通过某种方式实现 handleMessage 方法,这点与 Java 中对 Thread 的设计有异曲同工之处。
在Java中,如果我们想使用多线程,有两种办法:

1. 向 Thread 的构造函数传入一个 Runnable 对象,并实现 Runnable 的 run 方法
2. 无需向 Thread 的构造函数传入 Runnable 对象,但是要重写 Thread 本身的 run 方法

所以只要用过多线程 Thread,应该就对 Hanlder 这种需要实现 handleMessage 的两种方式了然于心了。
在之前分析 Handler(用法篇)的时候我们讲到过两种重要的方法:sendMessage() 和 post(),我们从源码角度进行进一步分析!

四 sendMessage


我们看下 sendMessage() 源码处理流程:

public final boolean sendMessage(Message msg) {    return sendMessageDelayed(msg, 0);
}

1.sendMessageDelayed

    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {        if (delayMillis < 0) {
            delayMillis = 0;
        }        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);     // 最终调 sendMessageAtTime()
    }

通过以上代码可以看书:sendMessage() 调用了 sendMessageDelayed() ,sendMessageDelayed() 又调用了 sendMessageAtTime()。

Handler 中还有 sendEmptyMessage() 方法:

    public final boolean sendEmptyMessage(int what)
    {        return sendEmptyMessageDelayed(what, 0);
    }    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;        return sendMessageDelayed(msg, delayMillis);
    }    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {        if (delayMillis < 0) {
            delayMillis = 0;
        }        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);     // 最终还是要调 sendMessageAtTime()
    }

由此可见所有的 sendMessage 方法和 sendEmptyMessage 最终都调用了 sendMessageAtTime 方法。

2.post

我们看下 post() 源码处理流程:

    public final boolean post(Runnable r)
    {       return  sendMessageDelayed(getPostMessage(r), 0);
    }

可以看到内部调用了 getPostMessage 方法,该方法传入一个 Runnable 对象,得到一个 Message 对象。

3.getPostMessage

getPostMessage() 的源码如下:

   private static Message getPostMessage(Runnable r) {
       Message m = Message.obtain();
       m.callback = r;       return m;
   }

通过上面的代码我们可以看到在 getPostMessage 方法中,我们创建了一个 Message 对象,并将传入的 Runnable 对象赋值给 Message 的 callback 成员字段,然后返回该 Message ,然后在 post 方法中该携带有 Runnable 信息的 Message 传入到 sendMessageDelayed 方法中。由此我们可以看到所有的 post 方法内部都需要借助 sendMessage 方法来实现,所以 post() 与 sendMessage() 并不是对立关系,而是 post() 依赖 sendMessage() ,所以 post() 方法可以通过 sendMessage() 方法向消息队列中传入消息,只不过通过 post() 方法向消息队列中传入的消息都携带有 Runnable 对象(Message.callback)。

五 sendMessageAtTime


通过分别分析 sendEmptyMessage()、post() 方法与 sendMessage() 方法之间的关系,我们可以看到在 Handler 中所有可以直接或间接向消息队列发送 Message 的方法最终都调用了 sendMessageAtTime 方法,该方法的源码如下:

   public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
       MessageQueue queue = mQueue;       if (queue == null) {
           RuntimeException e = new RuntimeException(                   this + " sendMessageAtTime() called with no mQueue");
           Log.w("Looper", e.getMessage(), e);           return false;
       }       return enqueueMessage(queue, msg, uptimeMillis);
   }

1.enqueueMessage

我们发现 sendMessageAtTime() 方法内部调用了 enqueueMessage() 函数:

   private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
       msg.target = this;       if (mAsynchronous) {
           msg.setAsynchronous(true);
       }       return queue.enqueueMessage(msg, uptimeMillis);
   }
我们需要重点注意两行代码:
msg.target = this; // 将 Message 的 target 绑定为当前的 Handler
// 变量 queue 表示的是 Handler 所绑定的消息队列 MessageQueue ,通过调用 queue.enqueueMessage(msg, uptimeMillis) 将 Message 放入到消息队列中。queue.enqueueMessage(msg, uptimeMillis);

还记得我们之前在分析 Looper 的时候,最终提到的 dispatchMessage() 吗?我们回忆一下:

           try {
               msg.target.dispatchMessage(msg);
               end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
           } finally {               if (traceTag != 0) {
                   Trace.traceEnd(traceTag);
               }
           }

六 MessageQueue


每个线程内部都维护了一个消息队列 —— MessageQueue。消息队列 MessageQueue,顾名思义,就是存放消息的队列。那队列中存储的消息是什么呢?

假设我们在UI界面上单击了某个按钮,而此时程序又恰好收到了某个广播事件,那我们如何处理这两件事呢?因为一个线程在某一时刻只能处理一件事情,不能同时处理多件事情,所以我们不能同时处理按钮的单击事件和广播事件,我们只能挨个对其进行处理,只要挨个处理就要有处理的先后顺序。

为此Android把UI界面上单击按钮的事件封装成了一个 Message ,将其放入到 MessageQueue 里面去,即将单击按钮事件的 Message 入栈到消息队列中,然后再将广播事件的封装成以 Message ,也将其入栈到消息队列中。

也就是说一个 Message 对象表示的是线程需要处理的一件事情,消息队列就是一堆需要处理的 Message 的池。线程 Thread 会依次取出消息队列中的消息,依次对其进行处理。

MessageQueue 中有两个比较重要的方法,一个是 enqueueMessage 方法,一个是 next 方法。enqueueMessage 方法用于将一个 Messag e放入到消息队列 MessageQueue 中,next 方法是从消息队列 MessageQueue 中阻塞式地取出一个 Message。在 Android 中,消息队列负责管理着顶级程序对象(Activity、BroadcastReceiver等)以及由其创建的所有窗口。

七 创建MessageQueue


   MessageQueue(boolean quitAllowed) {
       mQuitAllowed = quitAllowed;       // 通过 native 方法初始化消息队列,其中 mPtr 是供 native 代码使用
       mPtr = nativeInit();
   }

next()

   Message next() {       final long ptr = mPtr;       if (ptr == 0) {     // 当消息循环已经退出,则直接返回
           return null;
       }       // 循环迭代的首次为 -1
       int pendingIdleHandlerCount = -1; // -1 only during first iteration
       int nextPollTimeoutMillis = 0;       for (;;) {           if (nextPollTimeoutMillis != 0) {
               Binder.flushPendingCommands();
           }           // 阻塞操作,当等待 nextPollTimeoutMillis 时长,或者消息队列被唤醒,都会返回
           nativePollOnce(ptr, nextPollTimeoutMillis);           synchronized (this) {               // Try to retrieve the next message.  Return if found.
               final long now = SystemClock.uptimeMillis();
               Message prevMsg = null;
               Message msg = mMessages;               if (msg != null && msg.target == null) {                   // 当消息 Handler 为空时,查询 MessageQueue 中的下一条异步消息 msg,则退出循环
                   do {
                       prevMsg = msg;
                       msg = msg.next;
                   } while (msg != null && !msg.isAsynchronous());
               }               if (msg != null) {                   if (now < msg.when) {                       // 当异步消息触发时间大于当前时间,则设置下一次轮询的超时时长
                       nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                   } else {                       // 获取一条消息,并返回
                       mBlocked = false;                       if (prevMsg != null) {
                           prevMsg.next = msg.next;
                       } else {
                           mMessages = msg.next;
                       }
                       msg.next = null;                       // 设置消息的使用状态,即 flags |= FLAG_IN_USE
                       msg.markInUse();                       // 成功地获取 MessageQueue 中的下一条即将要执行的消息
                       return msg;
                   }
               } else {                   // 没有消息
                   nextPollTimeoutMillis = -1;
               }               // 消息正在退出,返回null
               if (mQuitting) {
                   dispose();                   return null;
               }               // 当消息队列为空,或者是消息队列的第一个消息时
               if (pendingIdleHandlerCount < 0
                       && (mMessages == null || now < mMessages.when)) {
                   pendingIdleHandlerCount = mIdleHandlers.size();
               }               if (pendingIdleHandlerCount <= 0) {               // 没有 idle handlers 需要运行,则循环并等待
                   mBlocked = true;                   continue;
               }               if (mPendingIdleHandlers == null) {
                   mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
               }
               mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
           }           // 只有第一次循环时,会运行 idle handlers,执行完成后,重置 pendingIdleHandlerCount 为 0
           for (int i = 0; i < pendingIdleHandlerCount; i++) {               final IdleHandler idler = mPendingIdleHandlers[i];
               mPendingIdleHandlers[i] = null; // 去掉 handler 的引用

               boolean keep = false;               try {
                   keep = idler.queueIdle();   // idle 时执行的方法
               } catch (Throwable t) {
                   Log.wtf(TAG, "IdleHandler threw exception", t);
               }               if (!keep) {                   synchronized (this) {
                       mIdleHandlers.remove(idler);
                   }
               }
           }           // 重置 idle handler 个数为 0,以保证不会再次重复运行
           pendingIdleHandlerCount = 0;           // 当调用一个空闲 handler 时,一个新 message 能够被分发,因此无需等待可以直接查询 pending message
           nextPollTimeoutMillis = 0;
       }
   }

nativePollOnce 是阻塞操作,其中 nextPollTimeoutMillis 代表下一个消息到来前,还需要等待的时长;当 nextPollTimeoutMillis = -1 时,表示消息队列中无消息,会一直等待下去。

当处于空闲时,往往会执行 IdleHandler 中的方法。当 nativePollOnce() 返回后,next() 从 mMessages 中提取一个消息。

八 enqueueMessage()

    boolean enqueueMessage(Message msg, long when) {        // 每一个普通 Message 必须有一个 target
        if (msg.target == null) {            throw new IllegalArgumentException("Message must have a target.");
        }        if (msg.isInUse()) {            throw new IllegalStateException(msg + " This message is already in use.");
        }        synchronized (this) {            // 正在退出时,回收 msg,加入到消息池
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;            boolean needWake;            if (p == null || when == 0 || when < p.when) {                // p 为 null (代表MessageQueue没有消息) 或者 msg 的触发时间是队列中最早的,则进入该该分支
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;   // 当阻塞时需要唤醒
            } else {                // 将消息按时间顺序插入到 MessageQueue。一般地,不需要唤醒事件队列,除非
                // 消息队头存在 barrier,并且同时 Message 是队列中最早的异步消息
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;                for (;;) {
                    prev = p;
                    p = p.next;                    if (p == null || when < p.when) {                        break;
                    }                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }            // 消息没有退出,我们认为此时 mPtr != 0
            if (needWake) {
                nativeWake(mPtr);
            }
        }        return true;
    }

MessageQueue 是按照 Message 触发时间的先后顺序排列的,队头的消息是将要最早触发的消息。当有消息需要加入消息队列时,会从队列头开始遍历,直到找到消息应该插入的合适位置,以保证所有消息的时间顺序。

九 removeMessages()


   void removeMessages(Handler h, int what, Object object) {       if (h == null) {           return;
       }       synchronized (this) {
           Message p = mMessages;           // 从消息队列的头部开始,移除所有符合条件的消息
           while (p != null && p.target == h && p.what == what
                  && (object == null || p.obj == object)) {
               Message n = p.next;
               mMessages = n;
               p.recycleUnchecked();
               p = n;
           }           // 移除剩余的符合要求的消息
           while (p != null) {
               Message n = p.next;               if (n != null) {                   if (n.target == h && n.what == what
                       && (object == null || n.obj == object)) {
                       Message nn = n.next;
                       n.recycleUnchecked();
                       p.next = nn;                       continue;
                   }
               }
               p = n;
           }
       }
   }

这个移除消息的方法,采用了两个 while 循环,第一个循环是从队头开始,移除符合条件的消息,第二个循环是从头部移除完连续的满足条件的消息之后,再从队列后面继续查询是否有满足条件的消息需要被移除。

总结


最后用一张图,来表示整个消息机制:


webp

63b637532d65d2a632369cbe8315b5bb_1460000016798930.jpg

图解:

     Handler通过sendMessage()发送Message到MessageQueue队列;
     Looper通过loop(),不断提取出达到触发条件的Message,并将Message交给target来处理;
     经过dispatchMessage()后,交回给Handler的handleMessage()来进行相应地处理。
     将Message加入MessageQueue时,处往管道写入字符,可以会唤醒loop线程;如果MessageQueue中没有Message,并处于Idle状态,则会执行IdelHandler接口中的方法,往往用于做一些清理性地工作。

想学习更多Android知识,或者获取相关资料请加入Android技术开发交流2群:935654177。本群可免费获取Gradle,RxJava,小程序,Hybrid,移动架构,NDK,React Native,性能优化等技术教程!

webp

面向Android中的一切实体.png



作者:Android征途
链接:https://www.jianshu.com/p/c38b8858124c


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 1
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消