android的线程间的通信可以理解成三个部分:消息的发送、消息的循环、消息的分发处理
消息是怎么发送的?
核心是理解sendMessage()里面做了哪些操作
- handler.sendMessage()
- handler.sendMessageDelayed()
- handler.sendMessageAtTime()
需要注意的是,sendMessageAtTime不是指要在这个时间插入这条消息,而是在这个时间将该消息分发出去
- handler.enqueueMessage()
- messageQueue.enqueueMessage()
- native->nativeWake()
- native->messageQueue.wake()
- native->mLooper.wake()
mWakeEventFd是一个计数器。
有两个线程,线程A和线程B
线程A有两种状态,运行、阻塞。监听eventfd事件的的navtive函数是阻塞的,当线程B往线程A消息队列发送消息,与此同时线程B通过eventfd写一个计数,此时会唤醒messageQueue中next函数内的无限for循环里面的,从messageQueue单链表中读取表头的操作
消息循环的过程是怎么样的?
消息循环是调用Looper.loop()
获取当前线程的looper,获取当前looper的messageQueue,开启无限循环,从messageQueue中读消息,如果msg为null,则阻塞,不为null,则将msg分发,其中target就是handler。以上有两个重点:
- queue.next()是如何获取消息的?
- msg.target.dispatchMessage(msg)是怎么分发消息的?
是如何处理消息分发的?
核心是理解dispatchMessage()里面做了什么操作
- 优先判断msg自身是否有callback,如果有,回调出去,即执行
msg.callback.run();
msg的callback是什么时候设置的呢?
是在handler.post(runnable)时候,执行sendMessageDelayed时,将Runnable对象赋值进message对象的callback中去
2. 判断handler是否有全局的callback,如果有,则掉全局的handleMessage函数。需要注意的是,如果回调的全局callback中的handleMessage函数,return 的是true,则不会再回调handler自身的handlerMessage函数,如果return的值是false,则会继续掉通handler自身的handlerMessage函数。一些hook技术就是通过设置全局的callback,并且handleMessage的返回值为false,中间修改msg的参数,这样,自身的handleMessage拿到的msg就是被修改之后的msg
3. 当前handler自身的handleMessage
从消息队列中获取下一条消息
在无限for循环中调用native层的nativePollOnce函数,这个函数其实是阻塞在for循环中的,目的是为了监听别的线程对当前线程喂消息,或者超时,就会唤醒返回,继续执行下面的代码。接着从消息队列(其实就是单链表)的表头取出一条消息,标记msg在使用中并返回。
是什么时候把msg标记为未使用的呢?
不是消息在recycle的时候,而是在Message.obtain()的时候,及将消息从空闲链表取出来的时候标记消息为未使用
超时时间默认为0,也就是说第一次无论如何都是会从消息队列读取消息的,如果没有读取到消息,这个超时时间可能就会被设置成-1了,会一直等待下次消息enqueue。
创建handler:
Looper.myLooper()获取当前线程的looper,判断当前线程是否有looper,如果没有,则需手动创建Looper.prepare(),否则抛出异常
在prepare函数中会从sThreadLocal.get()获取当前线程的looper,如果不为null,则抛出异常,提示每个线程只允许有一个Looper实例。如果为null,则new 一个Looper对象并将其保存在sThreadLocal中,sThreadLocal.set(new Looper(quiteAllowed)).Looper实例化的时候有做了什么呢,创建MessageQueue的java层实例,并用mThread变量保存looper当前的线程信息。在实例化java层的MessageQueue的时候,执行native层的init初始化函数,初始化native层的messageQueue,在初始化native层的messageQueue的时候,同时初始化native层的Looper
子线程
sendMessage()->sendMessageDelayed()->sendMessageAtTime()->enqueueMessage->nativeWake() 标记eventFD计数,唤醒Looper.looper()–>queue.next()的阻塞,dispatchMessage