用命令模式,手动模拟一下handler
import java.util.LinkedList;
import java.util.List;
// 接收者,真正的命令执行对象
class Handler {
public Handler(){}
void handleMessage(Message msg){
// TODO
}
void sendMsg(Message msg,Looper looper){
looper.enQueue(msg);
}
}
class Message {
Handler target;
public Message(){}
}
class Looper {
Message msg;
List<Message> MsgQueue = new LinkedList<>();
public Looper(){
// loop();
}
public void enQueue(Message msg){
MsgQueue.add(msg);
System.out.println("add success");
}
void loop(Handler handler){
for(;;){
if(!MsgQueue.isEmpty()){
handler.handleMessage(MsgQueue.get(0));
break;
}
}
}
}
class Activity {
public static void main(String[] args) {
Looper looper =new Looper();
looper.loop(handler);
Message msg = new Message();
Handler handler = new Handler(){
@Override
void handleMessage(Message msg) {
System.out.println("handle Message!");
};
};
handler.sendMsg(msg,looper);
}
}
发现好像并不奏效,一直在那循环,就是不输出,好奇怪。好像又不是那么奇怪,死循环本身就把线程阻塞了,这样好像也正常。
我们试着把looper.loop(handler)放在最后一行,居然生效了。
那Android里为什么没能卡死呢,确实是有这个死循环的啊,还在主线程,怎么做的呢。怀着好奇的心,又重新回去读源码。发现messageQueu#next()中很显眼的躺着一句:nativePollOnce(ptr, nextPollTimeoutMillis)
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMess
这里是个native方法,好像是这个问题的关键,但是又没办法继续看下去了。
Google一番才恍然大悟:或许可以把这个死循环看成socket,一直连接等待消息。其实实际上比socket要复杂一点,借助了Linux的epoll机制。简单理解一下,本质上就是多个socket发起连接,用一个程序都放在socket,程序响应之后,去查找是哪个socket这样的。
参考:如果这篇文章说不清epoll的本质,那就过来掐死我吧!)
其中还提到了select,最初发明的,程序响应后,再去一个一个遍历,看看是哪个socket响应了。而epoll高明之处就在于在这个程序中用地址对应socket,就不用挨个遍历了。