1.什么是Handler?为什么要用Handler
-
android在主线程中不建议做耗时操作(ANR),而子线程中更新UI是线程不安全的(Only the original thread that created a view hierarchy can touch its views)
-
Handler的作用就是通过使用Handler完成主线程和子线程信息的传递,从而达到刷新UI的效果
2.Handler涉及到的类
- ActivityThread
- ThreadLocal
- Message
- MessageQueue
- Loop
3.Handler如何将消息入列
-
在ActivityThread 中的main方法中调用Looper.prepareMainLooper->prepare(此处注意一个异常 Only one Looper may be created per thread) 初始化Looper 对象并将其交给ThreadLocal
ActivityThread.java
public static void main(String[] args) { ...省略 Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); ...省略 Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
Looper.java
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)); } public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
-
在Looper 的构造方法中初始化了MessageQueue
Looper.java
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
-
当调用handler.sendEmptyMessage->sendEmptyMessageDelayed->sendMessageDelayed->sendMessageAtTime->enqueueMessage 时时将当前Handler 对象通过msg.target=this 给Message 一个引用
Handler.java
public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); } public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } 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) { MessageQueue queue = mQueue; ...省略 return enqueueMessage(queue, msg, uptimeMillis); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
-
最后调用MessageQueue.enqueueMessage 将消息入列
MessageQueue.java
boolean enqueueMessage(Message msg, long when) { synchronized (this) { ...省略 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 { 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;
}
4.Handler如何消息出列
-
在ActivityThread 中的main方法中调用Looper.loop 方法
ActivityThread.java
public static void main(String[] args) { ...省略 Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); ...省略 Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
-
loop方法中的死循环不断调用MessageQueue.next将消息取出
Looper.java
public static void loop() { final Looper me = myLooper(); final MessageQueue queue = me.mQueue; ...省略 for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } ...省略 try { msg.target.dispatchMessage(msg); end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } ...省略 } }
-
每个Message都持有一个发送者(Handler)的引用,当取出 Message 后调用 msg.target.dispatchMessage(msg) 将消息发送到handlerMessage 或callBack 中
Handler.java
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
5.Looper.loop是个死循环为什么没有阻塞线程?
-
创建 Service、Activity 等包括执行其生命周期,最后都是交由 ActivityThread.H 处理,所以 Looper 虽然死循环,但是本质上我们UI的展示、更新,是通过 Handler 来处理,所以并不会造成真正的UI阻塞。
-
ActivityThread 实际上就是开启了一个消息循环,来执行 Activity、Service 等等的相关操作,一旦这个消息循环停止了,则意味着App进程也结束了。真正会卡死主线程的操作是在回调方法onCreate/onStart/onResume等操作时间过长,会导致掉帧,甚至发生ANR,looper.loop本身不会导致应用卡死。所以会阻塞,但是不会卡住。
-
那又会有另一个问题主线程的死循环一直运行是不是特别消耗CPU资源呢? 简单说就是在主线程的MessageQueue 没有消息时,便阻塞在**queue.next()中的nativePollOnce()**方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源
MessageQueue.java
Message next() { ...省略 for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis); ...省略 } }