系列之三 线程间通信-Handler 补充
系列目录 https://blog.csdn.net/jzlhll123/article/category/7671581
今天补充一个话题:
1. 是否可以对同一个Thread,Looper,建立2个Handler?
2. 如果可以,这2个Handler的运行顺序是否排队?是否可以相互接收到对方msg?
答案显然是:
1. 可以,使用Handler(Looper)创建多个;
2. 他们的消息是排队在线程内处理的,并且不能相互接收。
我们再次复习下Looper的源码。Looper的方法基本都是static的,这是因为Looper是跟Thread绑定的,一个thread只有一个Looper。原理:
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
第一步Looper.prepare()流程
:
sThreadLocal.set(new Looper(boolean)), 由于是静态的,一个进程多次prepare()会报错。这将Looper跟Thread绑定到一块,Looper成为了Thread的一个成员变量。
private Looper() { //构造函数
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
new Looper()的时候,会创建唯一的一个MessageQueue,因此,同一个Thread也只有一个Queue;
第二步loop()流程
:
public static final void loop() {
Looper me = myLooper(); //sThreadLocal.get()拿出来,线程唯一的一个变量
MessageQueue queue = me.mQueue;
//...
while (true) {
Message msg = queue.next(); //如果没事干就阻塞在这里
if (msg != null) {
if (msg.target == null) {
return;
}
//...
msg.target.dispatchMessage(msg);
//...
msg.recycle();
}
}
}
queue.next()里面 for (;;) { 开启了一个死循环,如果没有消息则会阻塞。
2. sendMessage
Handler new的时候,将looper传进去,成为成员变量mLooper
, 同时从mLooper拿出queue,也成为成员变量mQueue
. 因此,结合上面我们知道多个Handler其实共享同一个Looper,同一个messageQueue。
不论是sendMessage,sendMessageDelay,post等,最终都是sendMessageAtTime->enqueueMessage(queue, msg, uptimeMillis) 在这里给msg.target=this
,打上了跟每个具体Handler实例的印记(标注3)-> queue.enqueueMessage.
然后在MessageQueue代码中,给Message进一步根据是否有添加next节点等将所有的message进行一次队列串联。最后nativeWake
(标注2)。
3. dispatchMessage&handleMessage
我们来看标注1和标注2. 标注1处queue.next()内部会nativePollOnce
,达到一个等待的状态;标注2 msg过来以后唤醒了next()可以继续下去。(这就解释了Handler的模型)。
然后,next()返回,msg.target.dispatchMessage(msg);, 也就是标注3,这里将msg分发给具体的Handler。
最后独特的Handler自己的handleMessage(msg)
收到了自己的msg。
所以,使用的时候,我们可以创建多个Handler,但是可以通过控制Thread的个数,来让自己的一些业务逻辑排队。