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循环。
简单理解已到时间的消息会继续执行,延时消息直接清空