1 创建Handler
众所周知,在子线程直接创建Handler一定会报错,如图
1.png
意思也很明确,必须要调用Looper.prepare(),才能创建Handler,因为整个Handler的消息循环机制是建立在Looper之上.
那为什么主线程不用调用Looper.prepare就可以创建Handler呢?
因为在ActivityThread的main函数里面,帮我们调用了Looper.prepare()
public static void main(String[] args) {
//省略部分代码
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
而使用两次Looper.prepare()则会报一下错误
2.png
因为每个Thread仅仅只能获取一个Looper.
搞清楚了Looper.prepare,我们来看一下为什么必须要调用它才能创建Handler.
2 Looper.prepare
3.png4.png
5.png
6.png
而Looper的mQueue则是在构造函数中创建的,如图所示,即我们调用prepare的时候
到此,prepare的代码全部执行完了。
从上面的图6,可以看到prepare主要里是这句代码
sThreadLocal.set(new Looper(quitAllowed));
1 新建了一个Loopper对象
2 set到sThreadLocal里面
3 sThreadLocal又新建了一个Map来保存当前的key(即当前的Thread)与value(即新建的Looper)
4 Looper创建了MessageQueue
再来看new Handler做了什么事情
3 Handler构造函数
7.png可以看到这句 mLooper = Looper.myLooper();关键代码,将Looper.myLooper赋值给Handler自己的mLooper,不然就报那个知名的错误。
mQueue = mLooper.mQueue;//将looper的mQueue赋值给Handler的mQueue
8.pngimage.png
可以看到Looper.myLooper()是将prepare的里面创建的Looper再取出来。
可以得知 每次新建Handler的时候,得先将Looper创建好。
4 Looper.loop
一般我们创建好Handler之后,都需要在调用Looper.loop,我们看看它具体做了什么事情.
public static void loop() {
final Looper me = myLooper();
//省略部分无效代码
final MessageQueue queue = me.mQueue;
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);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//省略部分无效代码
msg.recycleUnchecked();
}
}
至此,我们可以看到,loop是获取了,MessageQueue,然后启动死循环,不断调用queue.next直到消息队列里,没有任何消息了,才跳出循环.
至此,创建Handler的部分结束了,我们来看看Handler如何SendMessage的
5 Handler.SendMessage
当我们调用SendMessage时候,最终会调用的方法是这个
9.png
10.png
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {// 如果是第一个进入到消息队列的消息且delay的时间最小(最小为0),则把其设置为消息队列的头
// 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) {//根据delay的时间决定插在队列的什么位置
break;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
}
return true;
}
可以看到,MessageQueue.enqueueMessage会将所有的被sendMessage发送的Message增加到链表里。
由于Looper.loop的里面调用queue.next()的关系,(一直查询是否有新消息到来),如果查询到新消息,则进行msg.target.dispatchMessage(msg)。而msg的target则是在enqueueMessage做msg.target = this了,既当前发送此消息的Handler.
此时又回到了Handler的dispatchMessage
6 Handler.dispatchMessage
11.png可以看到,dispatchMessage并没有做什么复杂的操作,仅仅就是判断了Message自身是否有CallBack,Handler是否设置了CallBack,如果都没有,则调用Handler的HandleMessage方法。
同步屏障
ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();//建立同步屏障
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); //发送消息
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
void unscheduleTraversals() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
mChoreographer.removeCallbacks(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
Choreographer.postCallback实际上调用了postCallbackDelayedInternal,可以看到setAsynchronous(true);即设置为异步消息。
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);//设置为异步消息
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
总结:
1 调用Looper.prepare是为了创建Looper,然后创建Map,根据CurrentThread保存Looper。Looper创建了MessageQueue
2 new Handler的时候会将Looper与Hanlder绑定,并且将Looper的MessageQueue与Handler的mQueue绑定
3 Looper.loop是为了启动消息循环不断查询(queue.next())是否有新消息到来,可能会阻塞
4 Handler.SendMessage则是将Message.target与Handler绑定,并且将Message插入到MessageQueue中去(根据delay插入,越小越前)
5 Looper.loop中查询到有新消息来了后,将会调用Message.target.dispatchMessage,将msg分发出去
6 Hanlder.dispatchMessage将进行msg的callback,Hanlder的callback判断,最后才调用HandleMessage.
即Message的CallBack优先级最高,Hanlder的CallBack其次,HandleMessage最低.
7 sThreadLocal是确保每个Thread里有且仅有一个Looper的关键,因为会去获取线程独有的ThreadLocal.ThreadLocalMap作为Map,然后把自己作为key,来保存looper,每次prepare则先会访问线程独有的ThreadLocal.ThreadLocalMap来判断是否有value
8 Message也分同步消息与异步消息,有两种方式发送异步消息, Message.setAsynchronous(True)与Hanlder.createAsync(),如果不设置则都为同步消息。在系统的ViewRootImpl里面Chreograher就是发送异步消息来绘制UI 即perfromTraversal会提前于所有同步消息执行
9 延时消息 是利用Message的when来对比,插入到哪里(小的前,大的后)
网友评论