Android『消息传递』
Hanlder构造方法
在创建Handler时,Handler在其构造方法中尝试从当前线程(创建Hanlder实例对象的线程)的ThreadLocal中取到Looper对象,并将该Looper对象赋值给当前Hanlder对象,同时还会将Looper对象的MessageQueue引用赋值给当前Handler。
//Lopper.myLooper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
//new Handler()
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Looper.prepare()
在子线程中尝试创建Handler对象时,检测当前线程是否已经关联Looper对象,不存在就报错(需要调用Looper.prepare()进行关联),存在的话直接返回当前线程关联的Looper对象,使Handler持有Looper和Looper.MessageQueue的引用,从而能够往MessageQueue中添加消息。一个线程最多只能创建一个Looper,但是多个Handler可以对应同一个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));
}
主线程中的Looper
在主线程中创建Handler不需要手动调用Looper.prepare(),因为主线程的ActivityThread变量在main方法中调用了prepareMainLooper()来初始化了主线程的Looper对象。
//ActivityThread.main()
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
}
sendMessage()和sendMessageAtTime()
Handler的sendMessage调用的是MessageQueue.enqueueMessage(Message,uptimeMillis),因为可能存在多个线程同时往同一个MessageQueue中插入Message,所以MessageQueue.enqueueMessage是同步方法。sendMessage()最终调用sendMessageAtTime(),只不过它的uptimeMillis参数为0,即不延时执行的意思。
//Handler.sendMessage()
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
//Hanlder.sendMessageDelayed
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
这里的uptimeMillis随Msg存入到MQ,而sendMessageDelayed()的延迟执行效果是有MQ在取出消息进行dispatch时完成的,取出消息时会比对当前时间和Msg的when属性。
//Handler.sendMessageAtTime()
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
//Handler.enqueueMessage()
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
//MessageQueue.enqueueMessage()
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
Looper.loop()
Looper调用loop()方法,其中不断从MessageQueue中取出Message(通过message.next()方法),进行dispatchMessage,其实在Handler调用sendMessage时已经将自己设置为Message.target了,所以dispatch只是将message发给自己的target处理而已。
主线程如何通过Handler发送Message通信
定义一个全局的Handler对象mHandler;在子线程A中初始化这个mHandler,并重写handlerMessage()方法;在子线程B中调用mHandler.obtainMessage()方法从Message类自带的Message Pool中返回一个Message对象,然后使用message.sendToTarget()方法,发送消息。
主线程的Looper.loop()一直无限循环,为何没有ANR?
//Looper.loop()
public static void loop() {
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
}
...
}
首先需要知道造成ANR的原因:
- 当前的事件没有机会得到处理(即主线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了)。
- 当前的事件正在处理,但没有及时完成。执行时间超过了ANR的阈值:按键事件 5s ,broadcast 10s、前台service无响应的超时时间为20秒,后台service为200秒。
这样就可以解释为什么主线程的Looper.loop()一直无限循环但是为什么没有造成ANR了,从上面的代码可以看出当没有Message需要处理时,主线程没有进行任何和造成ANR有关的事件的处理,虽然是在无限循环,但是比起频繁的开启、关闭消息循环动作,这样的开销反而更小吧。
转载请注明出处:https://www.jianshu.com/writer#/notebooks/14980289/notes/44701526/preview