目录
Handler机制流程以及用到的类:
1.Message: 实现 Parcelable,8个obtain(**)方法获得Message实例
2.Handler:创建Message然后借助Handler发送,之后在Handler的handleMessage()方法中获得刚才发送的Message对象,创建Handler之前要创建Looper对象
3.MessageQueue:数据结构是一个单向链表,mMessages变量保存链表的第一个元素,Message对象中next字段保存列表的下一个
4.Looper:死循环从MessageQueue中去除Message,交给相应的Handler处理
Handler发送消息的方法:
post
postAtTime
postDelayed
postAtFrontOfQueue
sendMessage
sendEmptyMessage
sendEmptyMessageDelayed
sendEmptyMessageAtTime
sendMessageDelayed
sendMessageAtTime
sendMessageAtFrontOfQueue
executeOrSendMessage
--------------------------------------> 以上方法全部都走Handler类中 enqueueMessage方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
消息入队列:
-> 由上面代码块第6行 走到 MessageQueue的 enqueueMessage (只展示关键代码)
boolean enqueueMessage(Message msg, long when) {
......
synchronized (this) {
......
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
1.取出当前的消息,如果消息等待时间为0或者小于当前消息的等待时间,直接插到当前消息的前面
2.如果不是上面的情况:循环遍历已经存在的消息,插入到等待时间 大于前一个并且 小于后一个的位置,排队。
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 {
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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
核心逻辑为:
1.取出当前的消息,如果消息等待时间为0或者小于当前消息的等待时间,直接插到当前消息的前面
2.如果不是上面的情况:循环遍历已经存在的消息,插入到等待时间 大于前一个并且 小于后一个的位置,排队。
总之让消息按照等待时间入队列,等待Looper取出
取出消息:
关键代码:
queue.next(); //调用的是MessageQueue中的 next() 方法
msg.target.dispathMessage(msg); //调用的是Handler中 dispatchMessage 方法
public static void loop() {
final Looper me = myLooper();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
......
msg.recycleUnchecked();
}
}
下面代码,MessageQueue next() 方法,中的nativePollOnce本地方法,此处发生了阻塞,
与阻塞对应的是唤醒机制在入队的时候enqueueMessage方法。
Java层的阻塞是通过native层的epoll监听文件描述符的写入事件来实现的,阻塞和唤醒都放到了native层
Message next() {
......
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
......
}
......
}
详细的原因请看这篇文章
消息处理:
调用的是Handler中 dispatchMessage 方法中的
handleCallback
handleMessage
两个方法
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
在子线程中进行UI操作:
除了正常的发送消息外,还有3个方法在子线程更新UI
1. Handler的post()方法
在java的子线程中,用post方法更新主线程的UI就可以这样写
public class MainActivity extends Activity {
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
// 在这里进行UI操作
}
});
}
}).start();
}
}
2. View的post()方法
public boolean post(Runnable action) {
Handler handler;
if (mAttachInfo != null) {
handler = mAttachInfo.mHandler;
} else {
ViewRoot.getRunQueue().post(action);
return true;
}
return handler.post(action);
}
3. Activity的runOnUiThread()方法
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
以上的三个方法都是调用了 handler的post方法实现了UI的更新,和 Handler的handleMessage没什么区别,只有视觉和思维上的区别
有关Handler的常见面试问题:
1. handler的 sendMessage post 最终走的是什么方法? 最终走到了MessageQueue的 enqueueMessage(msg, when)方法。
2. 发送delay消息的时候,消息是存储到哪里,是如何运行的? 存储到了MessageQueue中,利用等待时间在native层中阻塞取出
3.线程之间的交互的原理是什么?未知请给出合适答案