Handler在安卓中起到了很重要的作用,也是面试中经常被提问到的点,下面我们从源码来分析下Handler
首先,Handler在安卓中有什么作用?
1、因为安卓不能在主线程做耗时的操作,耗时操作需要在子线程中操作,但是子线程不能更新UI,因此需要Handler在子线程发消息给主线程来更新UI
其次,Handler的原理机制
Handler有4个对象handler、Message、MessageQueue、Looper;
1、MessageQueue:消息队列,相当于传送带,负责Message队列的传送与管理
2、Looper是流水线的发动机,不断的把消息从消息队列中取出来,交给Handler处理
3、Message相当于传送带上的产品
4、handler传送带最终将产品交给handler处理
handler调用sendMessager的时候会将Messager放入消息队列中,Looper在应用启动的时候,就已经启动了,在不停的循环,从消息队列中获取消息,如果有消息,将消息交给handler,handler调用handleMessage进行消息的处理
从源码分析Looper、MessageQueue
1、 Looper何时创建?Looper中两个重要的方法prepare()和loop()的作用?
android主线程在创建的时候会主动创建一个Looper
ActivityThread是安卓的主线程,在ActivityThread的main函数中创建了Looper
public static void main(String[] args) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");SamplingProfilerIntegration.start();// CloseGuard defaults to true and can be quite spammy. We// disable it here, but selectively enable it later (via// StrictMode) on debug builds, but using DropBox, not logs.CloseGuard.setEnabled(false);Environment.initForCurrentUser();// Set the reporter for event logging in libcoreEventLogger.setReporter(new EventLoggingReporter());// Make sure TrustedCertificateStore looks in the right place for CA certificatesfinal File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());TrustedCertificateStore.setDefaultUserDirectory(configDir);Process.setArgV0("<pre-initialized>");//创建LooerLooper.prepareMainLooper();ActivityThread thread = new ActivityThread();thread.attach(false);if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);//创建loop成功后,就开启消息队列的无线循环Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}
调用Looper.prepareMainLooper方法,创建Looper对象
public static void prepareMainLooper() {prepare(false);synchronized (Looper.class) {if (sMainLooper != null) {throw new IllegalStateException("The main Looper has already been prepared.");}sMainLooper = myLooper();}}
在prepare中创建Looper,并将Looper和当前线程绑定,在创建之前,会判断该线程中是否存在Looper,如果存在,会抛出异常,提示该线程已经创建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));}
new Looper创建Looper的时候:
private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();}
会新建一个MessageQueue消息队列,并获取当前线程的引用
Looper中另一个重要方法loop()是干什么的呢?
该方法主要是不断的从消息队列中拿消息,其源码如下:
/*** Run the message queue in this thread. Be sure to call* {@link #quit()} to end the loop.*/public static void loop() {//获取Looper对象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;// Make sure the identity of this thread is that of the local process,// and keep track of what that identity token actually is.Binder.clearCallingIdentity();final long ident = Binder.clearCallingIdentity();//循环获取消息队列中的消息for (;;) {Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}// This must be in a local variable, in case a UI event sets the loggerfinal Printer logging = me.mLogging;if (logging != null) {logging.println(">>>>> Dispatching to " + msg.target + " " +msg.callback + ": " + msg.what);}final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;final long traceTag = me.mTraceTag;if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {Trace.traceBegin(traceTag, msg.target.getTraceName(msg));}final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();final long end;try {msg.target.dispatchMessage(msg);end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();} finally {if (traceTag != 0) {Trace.traceEnd(traceTag);}}if (slowDispatchThresholdMs > 0) {final long time = end - start;if (time > slowDispatchThresholdMs) {Slog.w(TAG, "Dispatch took " + time + "ms on "+ Thread.currentThread().getName() + ", h=" +msg.target + " cb=" + msg.callback + " msg=" + msg.what);}}if (logging != null) {logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);}// Make sure that during the course of dispatching the// identity of the thread wasn't corrupted.final long newIdent = Binder.clearCallingIdentity();if (ident != newIdent) {Log.wtf(TAG, "Thread identity changed from 0x"+ Long.toHexString(ident) + " to 0x"+ Long.toHexString(newIdent) + " while dispatching to "+ msg.target.getClass().getName() + " "+ msg.callback + " what=" + msg.what);}msg.recycleUnchecked();}}
loop获取Looper对象,然后looper对象中获取MessageQueue对象,然后开启一个无限循环,这个循环就是不停的从MessageQueue中取消息,并将取出消息交给handler的dispatchMessage()来处理,只有当queue.next()取得Message为null的时候才跳出循环
public void dispatchMessage(Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}
最终将消息回调到handleMessage处理
Looper的其他方法
//获取当前线程的Looper
Looper looper = Looper.myLooper();
//获取主线的Looper
Looper mainLooper = Looper.getMainLooper();
//清除全部消息
looper.quit();
//清除延迟消息
looper.quitSafely();
handler调用不管是调用sendMessage、sendEmptyMessage、sendEmptyMessageDelayed都是调用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);}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);}
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.nextprev.next = msg;}// We can assume mPtr != 0 because mQuitting is false.if (needWake) {nativeWake(mPtr);}}return true;}
获取消息队列对象,并将消息插入到消息队列中
总结:在activity启动的时候,创建了Looper对象,创建Looper对象的时候,创建了MesageQueue队列,并开启MessageQueue的无限循环。当handler调用sendMessage发送消息的时候,会将Message插入到消息队列中,消息队列不停循环,当有消息的时候,Loope人取出消息,交给handler,handler回调handleMessage处理消息