MessageQueue和Looper的设计很巧妙,但是代码看上去很繁琐,我们不必了解其实现细节,知道其思路即可,这里我们探讨其基本原理,
调用Handler的post等方法后,会调用到MessageQueue的enqueueMessage来按照执行时间顺序来排列,最好理解的取队列数据的实现方案是,while执行循环,不断的取队列头部的数据,但显然不能这样做。
而Looper中使用epoll_wait来进行阻塞,在队列头部放入数据后,进行wake操作,通知Looper可以检查了,于是epoll_wait退出阻塞,判断队列头部数据的时间是否<=当前时间,符合的活,取出来,执行里面的操作处理。然后对新的队列头部数据进行同样的操作。
不符合,计算时间差,作为继续要等待的时间,传给epoll_wait,等到了时间,自动解除阻塞,进行下一步判断处理。
在处理的时候,只需要关注队列头部的数据的唤醒时间。
就是这样清楚。
关键就在于,epoll_wait可以1进行阻塞,2收到信号实时解除阻塞,3到达设定时间后解除阻塞
int epoll_wait(int epfd,struct epoll_event * events, int maxevents,int timeout);
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
synchronized (this) {
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
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 {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
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;
}
Looper.java
137 public static void loop() {
138 final Looper me = myLooper();
140 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
141 }
142 final MessageQueue queue = me.mQueue;
144 // Make sure the identity of this thread is that of the local process,
145 // and keep track of what that identity token actually is.
146 Binder.clearCallingIdentity();
147 final long ident = Binder.clearCallingIdentity();
149 // Allow overriding a threshold with a system prop. e.g.
150 // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
151 final int thresholdOverride =
152 SystemProperties.getInt("log.looper."
154 + Thread.currentThread().getName()
155 + ".slow", 0);
157 boolean slowDeliveryDetected = false;
159 for (;;) {
160 Message msg = queue.next(); // might block
162 // No message indicates that the message queue is quitting.
163 return;
164 }
166 // This must be in a local variable, in case a UI event sets the logger
167 final Printer logging = me.mLogging;
169 logging.println(">>>>> Dispatching to " + msg.target + " " +
170 msg.callback + ": " + msg.what);
171 }
173 final long traceTag = me.mTraceTag;
174 long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
175 long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
176 if (thresholdOverride > 0) {
177 slowDispatchThresholdMs = thresholdOverride;
178 slowDeliveryThresholdMs = thresholdOverride;
179 }
180 final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
181 final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
183 final boolean needStartTime = logSlowDelivery || logSlowDispatch;
184 final boolean needEndTime = logSlowDispatch;
186 if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
187 Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
188 }
190 final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
191 final long dispatchEnd;
192 try {
193 msg.target.dispatchMessage(msg);
194 dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
195 } finally {
198 }
199 }