Handler
Handler是Android中常用的线程间通信机制
Android是不允许在UI线程进行耗时的网络操作,所以一般会在工作线程中执行网络请求,得到返回数据后通知UI线程更新界面,这就可以通过Handler实现
流程分析
Handler
首先需要创建一个Handler,所以先看一下Handler的构造函数,Handler有几个版本的构造函数
Handler.java
1 | public Handler(Looper looper, Callback callback, boolean async) { |
这个构造函数接受三个参数,第一个指定对应的Looper,第二个指定全局的回调函数,第三个指定是同步还是异步
Handler.java
1 | public Handler(Callback callback, boolean async) { |
这个构造函数接受两个参数,没有传入Looper,Looper在构造函数中由Looper.myLooper()
创建
当mLooper为空时会抛出一个常见的异常,说明在创建Handler之前必须调用Looper.prepare()
由此我们获得了消息循环mLooper,消息队列mQueue,全局回调mCallback
Looper
Looper.java
1 | public static Looper myLooper() { |
myLooper()
返回了当前线程的一个Looper
Looper.java
1 | private static void prepare(boolean quitAllowed) { |
这个线程本地变量Looper是在prepare()
里创建的,如果反复调用则会抛异常,意思是一个线程只能有一个Looper
Looper.java
1 | private Looper(boolean quitAllowed) { |
Looper的构造函数里,创建了一个消息队列mQueue,并把当前的线程设置给mThread
MessageQueue
MessageQueue.java
1 | MessageQueue(boolean quitAllowed) { |
消息队列的构造函数,可见调用了Native层的相关函数nativeInit()
Message
定义了一个消息,包含了描述和可被发送给Handler的数据对象,这个对象包含两个额外的int域和一个额外的object域,允许你在很多场合不用做内存分配
尽管构造函数是public的,最好的方式是obtain()
或者obtainMessage()
,将从一个回收对象的池中获得对象
1 | public static Message obtain() { |
Message里面有一个next
的Message域,整个就是一个链式结构
所以sPool
也是一个消息池的链,在从池中取出sPool
这个消息时,sPool
本身被赋值为sPool.next
,池大小减1
1 | private static final int MAX_POOL_SIZE = 50; |
发送消息
一般通过sendMessage()
这系列的函数发送消息,都要获得一个Message,设置消息类型和内容,立即或延时发送消息,最终是调用sendMessageAtTime()
Handler.java
1 | public boolean sendMessageAtTime(Message msg, long uptimeMillis) { |
检查是否有消息队列,没有的话会抛异常,然后调用enqueueMessage()
把消息放入队列
Handler.java
1 | private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { |
首先设置了消息的target
字段为本Handler,然后调用MessageQueue的queueMessage()
方法
从enqueueMessage()
放进队列的消息的target
都被设置了值,而后面有判断target
为空的地方
MessageQueue
里有一个postSyncBarrier()
方法,用来添加一个同步屏障
消息分为同步和异步,同步屏障说明之后的同步消息不被处理,异步消息就不会被影响,Handler的默认构造设置mAsynchronous
为false
,即都是同步消息
MessageQueue.java
1 | private int postSyncBarrier(long when) { |
可以发现没有设置消息的target
字段,即为空,
MessageQueue.java
1 | boolean enqueueMessage(Message msg, long when) { |
处理消息
Looper在prepare()
之后,需要调用loop()
来开始消息循环
Looper.java
1 | public static void loop() { |
开始一个无限循环,调用next()
获得消息队列的下一条消息,这里可能阻塞,如果取得的消息为空则退出循环,否则获得target
字段,调用其dispatchMessage()
方法
Handler.java
1 | public void dispatchMessage(Message msg) { |
按如下顺序调用回调处理消息:
1.消息中设置的回调
2.全局回调的handleMessage()
3.Handler.handleMessage()
,由子类实现
MessageQueue.java
1 | Message next() { |
Native层实现
MessageQueue通过mPtr
变量保存NativeMessageQueue对象,从而使得MessageQueue成为Java层和Native层的枢纽,既能处理上层消息,也能处理Native层消息
Handler/Looper/Message这三大类Java层与Native层并没有任何的真正关联,只是分别在Java层和Native层的Handler消息模型中具有相似的功能。都是彼此独立的,各自实现相应的逻辑