Handler机制
- 是消息机制的暴露出来供使用的上层接口。
- 整个机制不仅仅是用来更新UI,还可以比如:在IntentService中也用到了handler,但是这里不是用来更新UI,而是用来作为消息队列,向工作线程 HandlerThread 发送任务消息。
工作流程
创建looper(包含mQueue):
Looper.prepare()
将会new
一个Looper对象,Looper构造函数中主要做的是创建 MessageQueue对象mQueue
(单链表数结构维护队列结构(FIFO),单链表插入和删除效率高)和获取当前线程对象mThread
,实现looper
和mQueue
、mThread
的绑定,这样就可以保证looper取到的消息(无论来自哪个线程),都会给到当前线程处理Looper.prepare()
将looper放入ThreadLocal<Looper> sThreadLocal
中备用;sThreadLocal
保证了当前线程之后取到的looper一定是当前线程的looper。ThreadLocal类是线程本地变量的容器。- 主线程的looper在创建主线程时已经被prepare()了,故不需要再调用
Looper.prepare()
,因为Android主线程ActivityThread
中已经做了对mainLooper的Looper.prepareMainLooper();
、Looper.loop()
操作; - ▲工作线程则必须在线程内调用
Looper.prepare()
、Looper.loop()
才能启动整个消息机制,并在线程结束或者不再需要使用消息机制时关闭loopLooper.quit()
创建Handler:
- 不传入looper参数时:
- 在哪个线程创建,handler对象中绑定的looper是就是对应的线程的looper对象
- 传入looper参数时:
- handler对象中绑定的就是传入的线程的looper,可以传入任意子线程或主线程的looper
- handler中包含了绑定的轮询获取消息的looper对象以及looper中绑定的用来暂存消息的队列mQueue,这样就保证了消息发送时,是发送到对应线程的mQueue中,并且是这个线程所属的looper负责取用
- handler中还包含了Callback接口,其中方法
handleMessage(Message msg)
在接收消息的线程处理消息(重写)
发送消息
- handler.sendMessage 最终走到 enqueueMessage,其中将每个msg的target赋值为当前handler对象,一以便之后在调用回调Callback
- 并将msg加入消息队列mQueue:
- 调用了
mQueue.enqueueMessage(Message msg, long when)
,其中主要做的是锁,以mQueue为对象锁(synchronized(this){...}
),确保同一只时间只能有一个消息加入到接收消息的线程的looper的mQueue中
- 调用了
接收消息
- looper中的loop()方法中,无限循环从mQueue中读取消息,如果mQueue.next()不为空则处理消息
- 处理消息:不为空的msg中获取target也就是发送了消息的handler,调用它dispatchMessage(msg)方法,其中调用了mCallback.handleMessage(msg),回调消息
在哪一步完成了线程的切换?
- 消息机制至少存在两个线程(主子 或 子子),在应用中看似一个任务由子线程切换到了主线程(比如),其实只是发了个消息而已。
- 这个过程中并没有什么神秘的切换线程操作。只是保证msg加入接收者线程的looper的mQueue时的同步(synchronized),消息msg并不是“threadLocal”的数据,而是进程内共享的,那么只要保证线程安全即可:
- 即上面讲到的:
调用了mQueue.enqueueMessage(Message msg, long when),其中主要做的是锁,以mQueue为对象锁(synchronized(this){...}),确保同一只时间只能有一个消息加入到接收消息的线程的looper的mQueue中
- 即上面讲到的: