我們知道Looper的工作機制就是不斷的從MessageQueue裏面獲取消息,沒有消息的時候則等待,直到有消息到來,看Looper的源碼發現阻塞等待和通知用的是linux的epoll,它是linux內核下高效的的異步喚醒機制。既然是等待和喚醒,那是不是隻用java就可以處理了。於是利用synchronized實現一個簡版的Looper
Message,裏面只是簡單的一個數據,並且簡單用string類型
public class Message {
public Handler target;
public Message next;
public String data;
public Message(String data) {
this.data = data;
}
@Override
public String toString() {
return "data:"+data;
}
}
然後是Handler,也只是發送和處理兩個簡單方法
public class Handler {
Looper looper;
public Handler(Looper looper) {
this.looper = looper;
}
public void handlerMsg(Message msg) {
System.out.println("[handlerMsg]"+Thread.currentThread().getName()+","+msg);
}
public void sendMsg(Message msg) {
System.out.println("[sendMsg]"+Thread.currentThread().getName()+","+msg);
msg.target = this;
looper.mQueue.enqueueMessage(msg);
}
}
然後是MessageQueue,一個enqueueMessage方法,存儲message,一個next方法,獲取message,一個quit方法,結束等待。
public class MessageQueue {
public Message mMessages;
private boolean mQuitting;
public Message nextMsg() {
synchronized (this) {
for(;;) {
Message p = mMessages;
if(p==null) {
try {
System.out.println("wait....");
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(mQuitting) {
return null;
}
p=mMessages;
mMessages=mMessages.next;
return p;
}
}
}
void quit() {
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
notifyAll();
}
}
public int size() {
int size=0;
Message p = mMessages;
while(p!=null) {
size++;
p=p.next;
};
return size;
}
public void enqueueMessage(Message msg) {
synchronized (this) {
if(mMessages==null) {
mMessages = msg;
}else {
Message pre= mMessages;
Message p = pre.next;
while(p!=null) {
pre=p;
p=p.next;
};
pre.next = msg;
}
notifyAll();
}
}
}
Looper就簡單了,從MessageQueue裏面不斷的獲取消息,處理消息。
public class Looper {
MessageQueue mQueue=new MessageQueue();
private static Looper sMainLooper;
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public void loop() {
for(;;) {
Message msg=mQueue.nextMsg();
if(msg==null) {
return;
}
msg.target.handlerMsg(msg);
}
}
public void quit() {
mQueue.quit();
}
public static void prepareMainLooper() {
prepare();
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
private static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
public static Looper myLooper() {
return sThreadLocal.get();
}
}
public class LooperTest {
static Handler handler;
public static void main(String[] args) throws Exception {
//模擬主線程
Thread mainThread=new Thread(new Runnable() {
@Override
public void run() {
Looper.prepareMainLooper();
handler=new Handler(Looper.getMainLooper());
Looper.getMainLooper().loop();
System.out.println("quit");
}
});
mainThread.setName("mainThead");
mainThread.start();
//延遲是等主線程的loop()執行
Thread.sleep(100);
//模擬其他線程,發送消息
Thread t=new Thread() {
@Override
public void run() {
// TODO Auto-generated method stub
handler.sendMsg(new Message("1"));
handler.sendMsg(new Message("2"));
handler.sendMsg(new Message("3"));
}
};
t.setName("otherThread1");
t.start();
//模擬其他線程,發送消息
Thread t2=new Thread() {
@Override
public void run() {
// TODO Auto-generated method stub
handler.sendMsg(new Message("4"));
handler.sendMsg(new Message("5"));
handler.sendMsg(new Message("6"));
}
};
t2.setName("otherThread2");
t2.start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//調用退出
Looper.getMainLooper().quit();
}
}).start();
}
}
打印的日誌如下。
wait....
[sendMsg]otherThread1,data:1
[sendMsg]otherThread1,data:2
[sendMsg]otherThread1,data:3
[sendMsg]otherThread2,data:4
[sendMsg]otherThread2,data:5
[sendMsg]otherThread2,data:6
[handlerMsg]mainThead,data:1
[handlerMsg]mainThead,data:2
[handlerMsg]mainThead,data:3
[handlerMsg]mainThead,data:4
[handlerMsg]mainThead,data:5
[handlerMsg]mainThead,data:6
wait....
quit
當然我們這個是簡單再簡單不過的版本,只有發送和處理,消息也沒有按照時間排序。但是處理整個流程和系統Looper大致相似。