- 我们看下基本的概念
- messagequeue===中文的翻译是消息队列,它的内部存储了一组消息,以队列的形式对外提供增加和删除的方法,但是他的内部不是队列的结构形式,而是采用单链表的数据结构来存储消息列表
- looper==轮询器,也可以理解为消息循环,由于messagequeue是一个消息容器,所以他负责不断的去轮训消息,如果有消息处理的话就去处理消息,否则就一直等待着。他还有一个特殊的概念threadlocal
,并不是线程,他的作用是在每个线程中存储数据,负责绑定当前的线程的loop
- 首先我们知道创建一个handel
new Handler();就行了但是其中内部干了什么呢?
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
//获取loper对象,如果lopper对象为空就会报异常,这就是为什么我们在子线程使用需要主动的调用 Looper.prepare();
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
我们看下Looper.prepare();的源码可以得知,只有sThreadLocal为空的时候起创建了一个Looper对象
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
那么为什么我们在主线程就没有调用就没事呢!
其实你在创建activitythred的内部就给你调用了Looper.prepareMainLooper()调用了Looper.prepare()方法,因此我们应用程序的主线程中会始终存在一个Looper对象,从而不需要再手动去调用Looper.prepare()方法了。
-
然后我们发送消息需要什么?
messag对message,我们看看怎么创建一个message,那么创建message有那些方式,2中,我们一般推荐使用 Message.obtain();为什么推荐这个我么你看下源码! //我们可以清楚,首先他会看Message对象是不是已经存在了,如果存在了就直接复用,没有直接创建,这样原因不说也明白了吧。 ` public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message();
}`
- 有了消息我们就要发送出去,如何发送呢!
`handler.sendMessage(message);`,这样我们就可以把消息发送出去。那么它里面是如何发送消息的,我们通过看源码得知他最终回调用sendMessageAtTime(),我们看下源码
//其中msg参数就是我们发送的Message对象,而uptimeMillis参数则表示发送消息的时间,它的值等于自系统开机到当前时间的毫秒数再加上延迟时间
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//如果quer为空就会停止轮训消息
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
//进入enqueueMessage
return enqueueMessage(queue, msg, uptimeMillis);
}
//通过看源码我们知道,MessageQueue是在调用looper的时候创建的,因此一个Looper也就对应了一个MessageQueue。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
我们看下enqueueMessage的方法,在这里进行消息的入队,将消息插入到messagequene
final boolean enqueueMessage(Message msg, long when) {
if (msg.when != 0) {
throw new AndroidRuntimeException(msg + " This message is already in use.");
}
//如果为空将报异常,msg.target就是handel
if (msg.target == null && !mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit");
}
synchronized (this) {
//如果调用了quit就会赋值为true
if (mQuiting) {
RuntimeException e = new RuntimeException(msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
} else if (msg.target == null) {
mQuiting = true;
}
msg.when = when;
Message p = mMessages;
//在这里他们将按照时间的顺序排列
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
this.notify();
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
this.notify();
}
}
if (needWake) {
//在native层进行消息的传递
nativeWake(mPtr);
}
return true;
}
- 接下来我们看下消息的轮训 loop.loop()
public static final void loop() {
//获取Looper
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
//这里面也是个死循环去取消息如果当前MessageQueue中存在mMessages(即待处理消息),就将这个消息出队,然后让下一条消息成为mMessages,否则就进入一个阻塞状态,一直等到有新的消息入队。
//MessageQueue中的nex方法,去轮训消息内部是一个无限的循环轮询,这里面要想退出这个无限的循环只有queue.next()
返回null,而要让他返回null,通过看源码mQuitting就行了,也就是说只要调用quit就可以了
Message msg = queue.next(); // might block
if (msg != null) {
//如果handel为空将直接退出循环
if (msg.target == null) {
return;
}
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
//这里就会调用handeld的dispatchMessage进行消息的分发,为什么是msg.target是handel通过源码我们看到enqueueMessage里面进行的赋值 msg.target = this;我们看下怎么分发的
msg.target.dispatchMessage(msg);
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle();
}
}
}
//我们进入到这个方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//这个方法熟悉把就把消息传递到我们重写的主线程的方法了,在这里进行回调handleMessage
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}