1. 主线程的Looper是什么时候创建的?
frameworks/base/core/java/android/app/ActivityThread.java 中的main函数
public static void main(String[] args) {
// 省略n行
Looper.prepareMainLooper();
// 省略n行
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// 省略n行
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
2. 即然用的是同一个队列,那怎么区分消息是由哪个handler接收呢?
发前消息时会将当前的Handler放到msg.target中.
当loop有收到新消息时调用msg.target.dispatchMsg将消息分发到对应的loop
// Handler.java
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
// Looper.java
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// 省略n行
for (;;) {
// 省略n行
Message msg = queue.next(); // might block
// 省略n行
try {
// 此处找到对应的handler进行消息分发
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
// 省略n行
msg.recycleUnchecked();
}
// 省略n行
}
3. 如何保证线程安全
往队列放或着获取msg时会用synchonize同步,保证安全
4. postDelay是怎么实现的?
andorid.os.MessgeQueue.java 队列会根据delay进行排队, 会调用nativenativePollOnce(ptr, nextPollTimeoutMillis) 进行等待.
放消息队列enqueMessage时会, 同时会调用nativeWait(ptr) 重新计算时间nextPollTimeoutMillis 重新调用nativenativePollOnce进行等待
5. handler内存泄露?
内部类持用外部类的对象, 当handleMessage持有activity时
message.target会持用Handler,Handler会持有用外部类
外部类生成的对象被message并放到messageQueue引用。
messageQueye=>message=>handler=>Activity
可以用软引用解决
6.loop线程如何退出?
message.quit() 会设置mQuiting= true, removeAllMessage nativeWait。
7. MailLoop调用quit会怎样?
主线程mQuitAllowed=false 会抛异常
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
8. Loop.quit()和Loop.quitSafely区别?
quit()实际上是把消息队列全部清空,然后让MessageQueue.next()返回null令Looper.loop()循环结束从而终止Handler机制,但是存在着不安全的地方是可能有些消息在消息队列没来得及处理。
而quitsafely()做了优化,只清除消息队列中延迟信息,等待消息队列剩余信息处理完之后再终止Looper循环。
简单理解已到时间的消息会继续执行,延时消息直接清空