学习并理解 handler,looper,message之间的关系
先看 Looper 源代码
private Looper() { **//3,创建Looper**
// 创建一个新的消息队列
mQueue = new MessageQueue();
mRun = true;
// 将创建的looper和当前线程绑定在一起
mThread = Thread.currentThread();
}
public static final void prepare() { //2,调用prepare()
// 这个判断保证一个线程只能有一个looper
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 创建一个looper存放在 ThreadLocal 中, ThreadLocal 的作用就是保证每个线程操作都是自己的对象
sThreadLocal.set(new Looper()); //3,创建Looper
}
public static final void prepareMainLooper() {// 1, 调用此方法创建 一个Looper
prepare(); // 2,调用prepare()
setMainLooper(myLooper());
if (Process.supportsProcesses()) {
myLooper().mQueue.mQuitAllowed = false;
}
}
public static final void loop() { // 4,loop方法
// 获取之前放在 ThreadLocal 中创建的 Looper对象和消息队列
Looper me = myLooper();
MessageQueue queue = me.mQueue;
.....
while (true) {
// 代码执行到这里会阻塞。。。 这时候跳到 第二大步骤
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
....
msg.target.dispatchMessage(msg); // 这个msg.target就是handler,用来区分不同的handler。
....
}
}
}
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
一,首先一个程序的启动时,他的UI线程(也就是主线程)会在main 方法中调用 Looper的静态方法
# ActivityThread.java 主线程中的部分代码
public static final void main(String[] args) {
.....
// 1, 调用此方法创建 一个Looper
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
.....
// 4,调用此死循环方法不断的从消息队列中读取消息。
Looper.loop();
}
二,关于handler,搞清楚前面的Looper 后 再来看看handler是怎么工作的
当我们在activity中创建handler写下下面代码时。
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {}
}
来看看他的构造函数
public Handler() {
….
// 这里又调用到了Looper.myLooper()方法,这里得到了UI线程之前创建的Looper。
mLooper = Looper.myLooper();
….
// 此处获得UI线程创建的消息队列
mQueue = mLooper.mQueue;
mCallback = null;
}
可以看到通过Handler() 构造函数 ,新建的handler对象和Looper对象,消息队列绑定在一起了。
总结 一,二 两大步骤可以知道 一个线程里面只有一个looper 和messagequeue,我们有时在activity中却可以创建多个handler的对象发送
消息,那么looper是如何识别不同的handler对象呢,最后跳到第三大步,发送message。
三,我们一般都会开启一个子线程进行一些耗时操作,然后在子线程中发送消息到主线程,主线程在执行更新ui的操作。
当我们使用handler.sendMessage(msg)时,看看handler的源码
public void handleMessage(Message msg) {
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
boolean sent = false;
// 得到消息队列
MessageQueue queue = mQueue;
if (queue != null) {
// 将当前发送message的对象赋值给msg.target属性,这个属性就是用来区分不同的handler
msg.target = this;
// 调用messagequeue的方法
sent = queue.enqueueMessage(msg, uptimeMillis);
} else {
RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
可以看到 最后调用sendMessageAtTime()这个方法,再来看看这个方法
得到消息队列
MessageQueue queue = mQueue;
if (queue != null) {
// 将当前发送message的对象赋值给msg.target属性,这个属性就是用来区分不同的handler
msg.target = this;
// 调用messagequeue的方法,
sent = queue.enqueueMessage(msg, uptimeMillis);
最后调用queue.enqueueMessage()方法,将消息添加到消息队列
来看看 MessageQueue.enqueueMessage 代码
final boolean enqueueMessage(Message msg, long when) {
...
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
// 当前发送的message需要马上被处理调,needWake唤醒状态置true
msg.next = p;
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
} else {
// 当前发送的message被排队到其他message的后面,needWake唤醒状态置false
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // still waiting on head, no need to wake up
}
}
// 是否唤醒主线程
if (needWake) {
nativeWake(mPtr);
}
return true;
}
当handler.sendMessage(msg)完成后,之前的UI线程的loop方法中 Message msg = queue.next()就不会再阻塞了,会依次执行下去
当执行到 msg.target.dispatchMessage(msg);方法时。可以看到hanlder源码最终执行的是 handleMessage()。而我们新建的handler 又重
写了这个方法。从而在主线程进行一些ui操作。
小结下,总的来说就是ui线程会在程序启动时,创建looper和消息队列,然后调用Looper的静态方法 loop(),这个方法中 message msg =
queue.next();//如果里面没有消息就会阻塞。如果Handler在主线程中创建,Looper会在死循环里等待取消息,1、没取到,就阻塞,2、一
旦被子线程唤醒,取到消息,就把Message交给Handler处理。子线程用Handler去发送消息,拿写入描述符去写消息,唤醒主线程。