目录
Message
Message中一些常见的参数与API
public final class Message implements Parcelable{
public int what; // 消息的id
public int arg1; // 整数参数1
public int arg2; // 整数参数2
public Object obj; // 任意类型参数
int flags; // 消息标记:正在使用异步还是同步
Bundle data; //消息附带的额外数据
long when; // 消息被处理的时间
Handler target; // 消息的接收与处理者
Messge next; // 下一个消息的指针
private static final Object sPoolSync = new Object(); // 消息池使用的对象锁
private static Message sPool; // 消息池
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50; // 消息池的最大容量,为什么设置为50
public static Messgae obtain(){} // 复用消息池中的消息
void recycleUnchecked(){} // 回收并清理消息(msg.target = null;sPool = this)
public void sendToTarget(){target.sendMessage(this);} // 发送给消息绑定的Handler
// 复用对象池中的消息对象
public static Message obtain() {
synchronized (sPoolSync) { // 加锁同步
if (sPool != null) {
Message m = sPool;
sPool = m.next; // 将指针移动到下一个节点
m.next = null; // 从链表中断开连接
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
// 回收消息对象
void recycleUnchecked() {
... 重置消息对象中的属性 ...
target = null; // 主动断开与 handler 的引用关系
// 形成消息池链表。注意:第一个插入的节点作为尾节点
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
}
小结:
1. 由于Message定义了下一个消息的指针,因此它组成了一个消息链表(重增删,轻查询);
2. 在Looper.loop()从消息队列中读取一个消息后,首先调用**msg.target.dispatchMessage(msg)** 将消息回传给 **handleMessage()**,最后调用**msg.recycleUncheckd()** 对消息进行重置回收。
3. 使用handler.obtainMessage()复用消息时,其实是从对象池链表中移除一个message对象再返回给调用者。
4. 在使用recycleUncheckd进行回收时,会主动断开与 handler 的引用关系。所以,handler并不会一定造成内存泄露
MessageQueue
MessageQueue中一些常见的参数与API
public final class MessageQueue{
public boolean mQuitAllowed;
Message mMessages; // 当前要处理的消息
private boolean mBlocked; // 表明线程是否阻塞在pollOnce上
private boolean mQuitting; // 是否主动退出循环
private void native nativePollOnce() // 阻塞线程
private void native static nativeWake(); // 唤醒被阻塞的线程
boolean enqueueMessage(msg){}
public int postSyncBarrier(){} // 发送一个同步屏障,阻塞同步消息
// 添加消息至消息队列
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
msg.markInUse(); // 标记为在用,不可被回收
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
Message prev;
// 从头开始遍历链表
for (;;) {
prev = p;
p = p.next;
// 到达尾节点或者消息执行时间靠前则返回
if (p == null || when < p.when) {
break;
}
}
// 插入消息队列中
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
}
return true;
}
// 读取消息
Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0; // native 线程阻塞的超时时间
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// 如果遇到消息屏障,则过滤掉同步消息,读取异步消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// 消息执行时间还没到,设置超时时间,期间阻塞在native层,不进行遍历,防止CPU占用
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; // 从队列中移出
msg.markInUse();
return msg;
}
} else {
// 没有可处理的消息
nextPollTimeoutMillis = -1;
}
// 在没有待处理消息时,如果通知退出,则执行退出
if (mQuitting) {
dispose();
return null;
}
// 处理 IdleHandler
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle(); // 执行 IdleHandler
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
// 移除队列中的所有消息
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked(); // 回收该消息
p = n;
}
mMessages = null;
}
}
小结:
1. MessageQueue采用链表来管理消息,其mMessages是当前要处理的消息;
2. Looper.loop中调用queue.next()函数, 从消息队列中读取一个消息,若队列中没有消息,则先处理 IdleHandler, 然后阻塞在nativePollOnce()上;若链表中有消息,则会检测当前消息是不是**同步屏障** ,若是则过滤所有的同步消息,只遍历获取异步消息,然后从链表中**删除并得到**该消息。
3. 调用enqueueMessage()向消息链表中添加消息,若链表中还没有消息,则直接作为消息链表的head,并调用nativeWake()唤醒阻塞在nativePollOnce()上的线程;若消息链表中有消息,比较 *msg.when* ,按照时间顺序添加进队列,检测是否需要调用nativeWake()。
4. 消息队列维护的消息链表是按照严格按照时间顺序排列的
5. 在从队列中移出消息时,会将该消息回收,添加到Message 的消息池中
Handler
Handler中的重要参数和API
public class Handler{
final Looper mLooper; // 循环读取消息队列中的消息的钩子
final MessageQueue mQueue; // Looper维护的消息队列
final Callback mCallback; // 处理消息的回调
// 指定Looper的构造函数
public Handler(Looper looper){
this.mLooper = looper;
this.mQueue = looper.mQueue;
***
}
// 不指定Looper的构造函数
public Handler(){
this.mLooper = Looper.myLooper(); // 通过ThreadLocal.get()获取该线程的Looper
if(mLooper == null){
throw RuntimeExcption("*********");
}
this.mQueue = mLooper.mQueue;
***
}
// 向消息队列添加消息
pulbic final boolean postDelayed(Runnable runnable, long delayMillis){
return sendMessageAtTime(getPostMessage(runnable), delayMillis);
}
public final boolean sendMessage(Message msg){
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);;
}
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r; // 指定了回调处理者
return m;
}
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
return false;
}
// 加入消息队列
return enqueueMessage(queue, msg, uptimeMillis);
}
// 移除指定消息
public final void removeMessage(int mhat){
mQueue.removeMessages(this, what, null);
}
// 移除所有的消息
public final void removeCallbacksAndMessages(Handler handler, Object obj){
mQueue.removeCallbacksAndMessage(this,obj);
}
// 复用Message
public final Message obtainMessage(){
return Message.obtain();
}
// 委派消息
public void dispatchMessage(Message msg){
if(msg.callback != null){ // 优先处理指定了消息处理者的消息
handleCallback(msg);
} else {
if(mCallback != null){
mCallback.handleMessage(msg);
}else{
handleMessage(msg);
}
}
}
// 处理消息的回调,子类必须实现
public void handleMessage(Message msg){}
}
小结:
1. Handler必须在含有Looper对象的线程中创建,可以在任意线程发送消息,处理消息的线程都是其对应的Looper所在的线程;由对应线程的loopr对象执行loop()方法,循环从维护的消息队列中读取消息,接着调用 *dispatchMessage* 分发并处理消息;
2. post系列的函数为待发送的消息指定了回调处理者Runnable,因此该消息交由Runnable处理;send系列函数则全部交由handleMessage(msg)处理。
3. 若在Activity或者Fragment中使用Handler向消息队列添加了消息,则在onDestrory时,主动调用removeMessage()对消息进行清理回收,防止Activity或者Fragment内存泄露;
Looper
一个线程只能有一个Looper,新创建的Looper实例将保存在对应线程的线程本地存储(ThreadLocal)中。
Looper维护了一个消息队列MessageQueue,该消息队列在Looper的构造方法中创建,属于该Looper对象所有。一个Looper只能有一个MessageQueue.
一个含有Looper实例的线程:
class LooperThread extends Thread {
Looper mLooper;
private @Nullable Handler mHandler;
public void run() {
Looper.prepare();
synchronized(this) {
mLooper = Looper.myLooper();
}
Looper.loop();
}
// 该方法必须在调用 start() 后调用。
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(mLooper)
}
return mHandler;
}
}
工作描述:
线程在运行状态,调用Looper.loop(),循环处理Looper维护的MessageQueue中的Message。消息添加到哪个消息队列和如何处理该消息,由Handler决定。指定了Looper就意味着指定了处理消息的线程;为消息指定的Handler则决定了用户如何处理该消息。
源码分析:
public final class Looper{
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); // 线程本地变量,由于是静态变量,所以可作为 GCRoots
private static Looper sMainLooper; // 主线程的Looper实例
final MessageQueue mQueue; // Looper维护的消息队列 由于是常量,所以可作为 GCRoots
final Thread mThread; // Looper所处的线程
// ActivityThread中的 调用Looper(false),意味着只有进程不在才退出messageQueue
private Looper(boolean quitAllowed){
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
public static void prepare(){
// 确保一个线程只能拥有一个Looper实例
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 通过ThreadLocal维护一个Looper实例
sThreadLocal.set(new Looper(true));
}
// 将looper升级为应用级别的实例对象。不建议在外调用
public static void prepareMainLooper(){
prepare();
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static Looper myLooper(){
return sThreadLocal.get();
}
// 循环读取维护的消息队列中的消息
public static void loop(){
final Looper me = myLooper();
if(me == null){
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
****
for(;;){
Message msg = queue.next(); // 可能会阻塞
if(msg == null){ // 表明调用了 quit,消息队列需要退出
return;
}
***
// 分发并处理消息msg
msg.target.dispatchMessage(msg);
// 清理并回收该消息,将清理后的干净消息添加进消息池
msg.recyleUncheckd();
}
}
}
小结:
1. 一个线程只有一个 Looper 实例,一个 Looper 实例维护一个 MessageQueue。
2. 消息在创建 Looper 实例的线程中被处理,消息可以在任意线程通过 handler 添加进消息队列。
问题:
1. 如果msg.next会阻塞主线程,那为什么程序运行时没感到卡顿那?
Handler的阻塞是通过底层的Looper.pollOnce(long delayMillis)实现的。pollOnce采用 *epoll* 机制(NIO机制的一种),在读取端阻塞时不会消耗CPU资源,所以不存在竞争资源的问题,因此不会感到卡顿。
2. 我们知道:handler 发送消息的线程与处理消息的线程可以不一样(多线程通信),那么是如何保证同步的那?
答案是 Looper 使用了 ThreadLocal 持有 Looper 实例,意味着每一个线程都会有 Looper实例 的一个副本。
ThreadLocal
总结
Handler通信机制采用循环等待/唤醒机制,通过handler的post/send系列函数向Looper维护的消息队列中添加消息时,会唤醒阻塞在nativePollOnce处的线程,在Looper.loop循环中读取消息,然后使用handler分发处理该消息.